<!DOCTYPE html>

<html lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="mobile-web-app-capable" content="yes">
    <title>
        Atomic Reduction Operations
    </title>

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css" integrity="sha256-vtR0hSWRc3Tb26iuN2oZHt3KRUomwTufNIf5/4oeCyg=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@hackmd/emojify.js@2.1.0/dist/css/basic/emojify.min.css" integrity="sha256-UOrvMOsSDSrW6szVLe8ZDZezBxh5IoIfgTwdNDgTjiU=" crossorigin="anonymous" />
    <style>
        @import url(https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i|Source+Code+Pro:300,400,500|Source+Sans+Pro:300,300i,400,400i,600,600i|Source+Serif+Pro&subset=latin-ext);
/*!
  Theme: GitHub
  Description: Light theme as seen on github.com
  Author: github.com
  Maintainer: @Hirse
  Updated: 2021-05-15

  Outdated base version: https://github.com/primer/github-syntax-light
  Current colors taken from GitHub's CSS
*/:root[theme=light] :not([theme])>*>.markdown-body .hljs-doctag,:root[theme=light] :not([theme])>*>.markdown-body .hljs-keyword,:root[theme=light] :not([theme])>*>.markdown-body .hljs-meta .hljs-keyword,:root[theme=light] :not([theme])>*>.markdown-body .hljs-template-tag,:root[theme=light] :not([theme])>*>.markdown-body .hljs-template-variable,:root[theme=light] :not([theme])>*>.markdown-body .hljs-type,:root[theme=light] :not([theme])>*>.markdown-body .hljs-variable.language_,:root[theme] [theme=light] .markdown-body .hljs-doctag,:root[theme] [theme=light] .markdown-body .hljs-keyword,:root[theme] [theme=light] .markdown-body .hljs-meta .hljs-keyword,:root[theme] [theme=light] .markdown-body .hljs-template-tag,:root[theme] [theme=light] .markdown-body .hljs-template-variable,:root[theme] [theme=light] .markdown-body .hljs-type,:root[theme] [theme=light] .markdown-body .hljs-variable.language_{color:#d73a49}:root[theme=light] :not([theme])>*>.markdown-body .hljs-title,:root[theme=light] :not([theme])>*>.markdown-body .hljs-title.class_,:root[theme=light] :not([theme])>*>.markdown-body .hljs-title.class_.inherited__,:root[theme=light] :not([theme])>*>.markdown-body .hljs-title.function_,:root[theme] [theme=light] .markdown-body .hljs-title,:root[theme] [theme=light] .markdown-body .hljs-title.class_,:root[theme] [theme=light] .markdown-body .hljs-title.class_.inherited__,:root[theme] [theme=light] .markdown-body .hljs-title.function_{color:#6f42c1}:root[theme=light] :not([theme])>*>.markdown-body .hljs-attr,:root[theme=light] :not([theme])>*>.markdown-body .hljs-attribute,:root[theme=light] :not([theme])>*>.markdown-body .hljs-literal,:root[theme=light] :not([theme])>*>.markdown-body .hljs-meta,:root[theme=light] :not([theme])>*>.markdown-body .hljs-number,:root[theme=light] :not([theme])>*>.markdown-body .hljs-operator,:root[theme=light] :not([theme])>*>.markdown-body .hljs-selector-attr,:root[theme=light] :not([theme])>*>.markdown-body .hljs-selector-class,:root[theme=light] :not([theme])>*>.markdown-body .hljs-selector-id,:root[theme=light] :not([theme])>*>.markdown-body .hljs-variable,:root[theme] [theme=light] .markdown-body .hljs-attr,:root[theme] [theme=light] .markdown-body .hljs-attribute,:root[theme] [theme=light] .markdown-body .hljs-literal,:root[theme] [theme=light] .markdown-body .hljs-meta,:root[theme] [theme=light] .markdown-body .hljs-number,:root[theme] [theme=light] .markdown-body .hljs-operator,:root[theme] [theme=light] .markdown-body .hljs-selector-attr,:root[theme] [theme=light] .markdown-body .hljs-selector-class,:root[theme] [theme=light] .markdown-body .hljs-selector-id,:root[theme] [theme=light] .markdown-body .hljs-variable{color:#005cc5}:root[theme=light] :not([theme])>*>.markdown-body .hljs-meta .hljs-string,:root[theme=light] :not([theme])>*>.markdown-body .hljs-regexp,:root[theme=light] :not([theme])>*>.markdown-body .hljs-string,:root[theme] [theme=light] .markdown-body .hljs-meta .hljs-string,:root[theme] [theme=light] .markdown-body .hljs-regexp,:root[theme] [theme=light] .markdown-body .hljs-string{color:#032f62}:root[theme=light] :not([theme])>*>.markdown-body .hljs-built_in,:root[theme=light] :not([theme])>*>.markdown-body .hljs-symbol,:root[theme] [theme=light] .markdown-body .hljs-built_in,:root[theme] [theme=light] .markdown-body .hljs-symbol{color:#e36209}:root[theme=light] :not([theme])>*>.markdown-body .hljs-code,:root[theme=light] :not([theme])>*>.markdown-body .hljs-comment,:root[theme=light] :not([theme])>*>.markdown-body .hljs-formula,:root[theme] [theme=light] .markdown-body .hljs-code,:root[theme] [theme=light] .markdown-body .hljs-comment,:root[theme] [theme=light] .markdown-body .hljs-formula{color:#6a737d}:root[theme=light] :not([theme])>*>.markdown-body .hljs-name,:root[theme=light] :not([theme])>*>.markdown-body .hljs-quote,:root[theme=light] :not([theme])>*>.markdown-body .hljs-selector-pseudo,:root[theme=light] :not([theme])>*>.markdown-body .hljs-selector-tag,:root[theme] [theme=light] .markdown-body .hljs-name,:root[theme] [theme=light] .markdown-body .hljs-quote,:root[theme] [theme=light] .markdown-body .hljs-selector-pseudo,:root[theme] [theme=light] .markdown-body .hljs-selector-tag{color:#22863a}:root[theme=light] :not([theme])>*>.markdown-body .hljs-subst,:root[theme] [theme=light] .markdown-body .hljs-subst{color:#24292e}:root[theme=light] :not([theme])>*>.markdown-body .hljs-section,:root[theme] [theme=light] .markdown-body .hljs-section{color:#005cc5;font-weight:700}:root[theme=light] :not([theme])>*>.markdown-body .hljs-bullet,:root[theme] [theme=light] .markdown-body .hljs-bullet{color:#735c0f}:root[theme=light] :not([theme])>*>.markdown-body .hljs-emphasis,:root[theme] [theme=light] .markdown-body .hljs-emphasis{color:#24292e;font-style:italic}:root[theme=light] :not([theme])>*>.markdown-body .hljs-strong,:root[theme] [theme=light] .markdown-body .hljs-strong{color:#24292e;font-weight:700}:root[theme=light] :not([theme])>*>.markdown-body .hljs-addition,:root[theme] [theme=light] .markdown-body .hljs-addition{background-color:#f0fff4;color:#22863a}:root[theme=light] :not([theme])>*>.markdown-body .hljs-deletion,:root[theme] [theme=light] .markdown-body .hljs-deletion{background-color:#ffeef0;color:#b31d28}

/*!
  Theme: GitHub Dark Dimmed
  Description: Dark dimmed theme as seen on github.com
  Author: github.com
  Maintainer: @Hirse
  Updated: 2021-05-15

  Colors taken from GitHub's CSS
*/:root[theme=dark] :not([theme])>*>.markdown-body .hljs-doctag,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-keyword,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-meta .hljs-keyword,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-template-tag,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-template-variable,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-type,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-variable.language_,:root[theme] [theme=dark] .markdown-body .hljs-doctag,:root[theme] [theme=dark] .markdown-body .hljs-keyword,:root[theme] [theme=dark] .markdown-body .hljs-meta .hljs-keyword,:root[theme] [theme=dark] .markdown-body .hljs-template-tag,:root[theme] [theme=dark] .markdown-body .hljs-template-variable,:root[theme] [theme=dark] .markdown-body .hljs-type,:root[theme] [theme=dark] .markdown-body .hljs-variable.language_{color:#f47067}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-title,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-title.class_,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-title.class_.inherited__,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-title.function_,:root[theme] [theme=dark] .markdown-body .hljs-title,:root[theme] [theme=dark] .markdown-body .hljs-title.class_,:root[theme] [theme=dark] .markdown-body .hljs-title.class_.inherited__,:root[theme] [theme=dark] .markdown-body .hljs-title.function_{color:#dcbdfb}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-attr,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-attribute,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-literal,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-meta,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-number,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-operator,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-selector-attr,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-selector-class,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-selector-id,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-variable,:root[theme] [theme=dark] .markdown-body .hljs-attr,:root[theme] [theme=dark] .markdown-body .hljs-attribute,:root[theme] [theme=dark] .markdown-body .hljs-literal,:root[theme] [theme=dark] .markdown-body .hljs-meta,:root[theme] [theme=dark] .markdown-body .hljs-number,:root[theme] [theme=dark] .markdown-body .hljs-operator,:root[theme] [theme=dark] .markdown-body .hljs-selector-attr,:root[theme] [theme=dark] .markdown-body .hljs-selector-class,:root[theme] [theme=dark] .markdown-body .hljs-selector-id,:root[theme] [theme=dark] .markdown-body .hljs-variable{color:#6cb6ff}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-meta .hljs-string,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-regexp,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-string,:root[theme] [theme=dark] .markdown-body .hljs-meta .hljs-string,:root[theme] [theme=dark] .markdown-body .hljs-regexp,:root[theme] [theme=dark] .markdown-body .hljs-string{color:#96d0ff}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-built_in,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-symbol,:root[theme] [theme=dark] .markdown-body .hljs-built_in,:root[theme] [theme=dark] .markdown-body .hljs-symbol{color:#f69d50}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-code,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-comment,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-formula,:root[theme] [theme=dark] .markdown-body .hljs-code,:root[theme] [theme=dark] .markdown-body .hljs-comment,:root[theme] [theme=dark] .markdown-body .hljs-formula{color:#768390}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-name,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-quote,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-selector-pseudo,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-selector-tag,:root[theme] [theme=dark] .markdown-body .hljs-name,:root[theme] [theme=dark] .markdown-body .hljs-quote,:root[theme] [theme=dark] .markdown-body .hljs-selector-pseudo,:root[theme] [theme=dark] .markdown-body .hljs-selector-tag{color:#8ddb8c}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-subst,:root[theme] [theme=dark] .markdown-body .hljs-subst{color:#adbac7}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-section,:root[theme] [theme=dark] .markdown-body .hljs-section{color:#316dca;font-weight:700}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-bullet,:root[theme] [theme=dark] .markdown-body .hljs-bullet{color:#eac55f}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-emphasis,:root[theme] [theme=dark] .markdown-body .hljs-emphasis{color:#adbac7;font-style:italic}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-strong,:root[theme] [theme=dark] .markdown-body .hljs-strong{color:#adbac7;font-weight:700}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-addition,:root[theme] [theme=dark] .markdown-body .hljs-addition{background-color:#1b4721;color:#b4f1b4}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-deletion,:root[theme] [theme=dark] .markdown-body .hljs-deletion{background-color:#78191b;color:#ffd8d3}:root[theme=dark] :not([theme])>*>.markdown-body code[class*=language-],:root[theme=dark] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=dark] .markdown-body code[class*=language-],:root[theme] [theme=dark] .markdown-body pre[class*=language-]{word-wrap:normal;background:none;color:#ccc;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;-webkit-hyphens:none;hyphens:none;line-height:1.5;tab-size:4;text-align:left;white-space:pre;word-break:normal;word-spacing:normal}:root[theme=dark] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=dark] .markdown-body pre[class*=language-]{margin:.5em 0;overflow:auto;padding:1em}:root[theme=dark] :not([theme])>*>.markdown-body :not(pre)>code[class*=language-],:root[theme=dark] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=dark] .markdown-body :not(pre)>code[class*=language-],:root[theme] [theme=dark] .markdown-body pre[class*=language-]{background:#2d2d2d}:root[theme=dark] :not([theme])>*>.markdown-body :not(pre)>code[class*=language-],:root[theme] [theme=dark] .markdown-body :not(pre)>code[class*=language-]{border-radius:.3em;padding:.1em;white-space:normal}:root[theme=dark] :not([theme])>*>.markdown-body .token.block-comment,:root[theme=dark] :not([theme])>*>.markdown-body .token.cdata,:root[theme=dark] :not([theme])>*>.markdown-body .token.comment,:root[theme=dark] :not([theme])>*>.markdown-body .token.doctype,:root[theme=dark] :not([theme])>*>.markdown-body .token.prolog,:root[theme] [theme=dark] .markdown-body .token.block-comment,:root[theme] [theme=dark] .markdown-body .token.cdata,:root[theme] [theme=dark] .markdown-body .token.comment,:root[theme] [theme=dark] .markdown-body .token.doctype,:root[theme] [theme=dark] .markdown-body .token.prolog{color:#999}:root[theme=dark] :not([theme])>*>.markdown-body .token.punctuation,:root[theme] [theme=dark] .markdown-body .token.punctuation{color:#ccc}:root[theme=dark] :not([theme])>*>.markdown-body .token.attr-name,:root[theme=dark] :not([theme])>*>.markdown-body .token.deleted,:root[theme=dark] :not([theme])>*>.markdown-body .token.namespace,:root[theme=dark] :not([theme])>*>.markdown-body .token.tag,:root[theme] [theme=dark] .markdown-body .token.attr-name,:root[theme] [theme=dark] .markdown-body .token.deleted,:root[theme] [theme=dark] .markdown-body .token.namespace,:root[theme] [theme=dark] .markdown-body .token.tag{color:#e2777a}:root[theme=dark] :not([theme])>*>.markdown-body .token.function-name,:root[theme] [theme=dark] .markdown-body .token.function-name{color:#6196cc}:root[theme=dark] :not([theme])>*>.markdown-body .token.boolean,:root[theme=dark] :not([theme])>*>.markdown-body .token.function,:root[theme=dark] :not([theme])>*>.markdown-body .token.number,:root[theme] [theme=dark] .markdown-body .token.boolean,:root[theme] [theme=dark] .markdown-body .token.function,:root[theme] [theme=dark] .markdown-body .token.number{color:#f08d49}:root[theme=dark] :not([theme])>*>.markdown-body .token.class-name,:root[theme=dark] :not([theme])>*>.markdown-body .token.constant,:root[theme=dark] :not([theme])>*>.markdown-body .token.property,:root[theme=dark] :not([theme])>*>.markdown-body .token.symbol,:root[theme] [theme=dark] .markdown-body .token.class-name,:root[theme] [theme=dark] .markdown-body .token.constant,:root[theme] [theme=dark] .markdown-body .token.property,:root[theme] [theme=dark] .markdown-body .token.symbol{color:#f8c555}:root[theme=dark] :not([theme])>*>.markdown-body .token.atrule,:root[theme=dark] :not([theme])>*>.markdown-body .token.builtin,:root[theme=dark] :not([theme])>*>.markdown-body .token.important,:root[theme=dark] :not([theme])>*>.markdown-body .token.keyword,:root[theme=dark] :not([theme])>*>.markdown-body .token.selector,:root[theme] [theme=dark] .markdown-body .token.atrule,:root[theme] [theme=dark] .markdown-body .token.builtin,:root[theme] [theme=dark] .markdown-body .token.important,:root[theme] [theme=dark] .markdown-body .token.keyword,:root[theme] [theme=dark] .markdown-body .token.selector{color:#cc99cd}:root[theme=dark] :not([theme])>*>.markdown-body .token.attr-value,:root[theme=dark] :not([theme])>*>.markdown-body .token.char,:root[theme=dark] :not([theme])>*>.markdown-body .token.regex,:root[theme=dark] :not([theme])>*>.markdown-body .token.string,:root[theme=dark] :not([theme])>*>.markdown-body .token.variable,:root[theme] [theme=dark] .markdown-body .token.attr-value,:root[theme] [theme=dark] .markdown-body .token.char,:root[theme] [theme=dark] .markdown-body .token.regex,:root[theme] [theme=dark] .markdown-body .token.string,:root[theme] [theme=dark] .markdown-body .token.variable{color:#7ec699}:root[theme=dark] :not([theme])>*>.markdown-body .token.entity,:root[theme=dark] :not([theme])>*>.markdown-body .token.operator,:root[theme=dark] :not([theme])>*>.markdown-body .token.url,:root[theme] [theme=dark] .markdown-body .token.entity,:root[theme] [theme=dark] .markdown-body .token.operator,:root[theme] [theme=dark] .markdown-body .token.url{color:#67cdcc}:root[theme=dark] :not([theme])>*>.markdown-body .token.bold,:root[theme=dark] :not([theme])>*>.markdown-body .token.important,:root[theme] [theme=dark] .markdown-body .token.bold,:root[theme] [theme=dark] .markdown-body .token.important{font-weight:700}:root[theme=dark] :not([theme])>*>.markdown-body .token.italic,:root[theme] [theme=dark] .markdown-body .token.italic{font-style:italic}:root[theme=dark] :not([theme])>*>.markdown-body .token.entity,:root[theme] [theme=dark] .markdown-body .token.entity{cursor:help}:root[theme=dark] :not([theme])>*>.markdown-body .token.inserted,:root[theme] [theme=dark] .markdown-body .token.inserted{color:green}:root[theme=light] :not([theme])>*>.markdown-body code[class*=language-],:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=light] .markdown-body code[class*=language-],:root[theme] [theme=light] .markdown-body pre[class*=language-]{word-wrap:normal;background:none;color:#000;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;-webkit-hyphens:none;hyphens:none;line-height:1.5;tab-size:4;text-align:left;text-shadow:0 1px #fff;white-space:pre;word-break:normal;word-spacing:normal}:root[theme=light] :not([theme])>*>.markdown-body code[class*=language-] ::selection,:root[theme=light] :not([theme])>*>.markdown-body code[class*=language-]::selection,:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-] ::selection,:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-]::selection,:root[theme] [theme=light] .markdown-body code[class*=language-] ::selection,:root[theme] [theme=light] .markdown-body code[class*=language-]::selection,:root[theme] [theme=light] .markdown-body pre[class*=language-] ::selection,:root[theme] [theme=light] .markdown-body pre[class*=language-]::selection{background:#b3d4fc;text-shadow:none}:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=light] .markdown-body pre[class*=language-]{margin:.5em 0;overflow:auto;padding:1em}:root[theme=light] :not([theme])>*>.markdown-body :not(pre)>code[class*=language-],:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=light] .markdown-body :not(pre)>code[class*=language-],:root[theme] [theme=light] .markdown-body pre[class*=language-]{background:#f5f2f0}:root[theme=light] :not([theme])>*>.markdown-body :not(pre)>code[class*=language-],:root[theme] [theme=light] .markdown-body :not(pre)>code[class*=language-]{border-radius:.3em;padding:.1em;white-space:normal}:root[theme=light] :not([theme])>*>.markdown-body .token.cdata,:root[theme=light] :not([theme])>*>.markdown-body .token.comment,:root[theme=light] :not([theme])>*>.markdown-body .token.doctype,:root[theme=light] :not([theme])>*>.markdown-body .token.prolog,:root[theme] [theme=light] .markdown-body .token.cdata,:root[theme] [theme=light] .markdown-body .token.comment,:root[theme] [theme=light] .markdown-body .token.doctype,:root[theme] [theme=light] .markdown-body .token.prolog{color:#708090}:root[theme=light] :not([theme])>*>.markdown-body .token.punctuation,:root[theme] [theme=light] .markdown-body .token.punctuation{color:#999}:root[theme=light] :not([theme])>*>.markdown-body .token.namespace,:root[theme] [theme=light] .markdown-body .token.namespace{opacity:.7}:root[theme=light] :not([theme])>*>.markdown-body .token.boolean,:root[theme=light] :not([theme])>*>.markdown-body .token.constant,:root[theme=light] :not([theme])>*>.markdown-body .token.deleted,:root[theme=light] :not([theme])>*>.markdown-body .token.number,:root[theme=light] :not([theme])>*>.markdown-body .token.property,:root[theme=light] :not([theme])>*>.markdown-body .token.symbol,:root[theme=light] :not([theme])>*>.markdown-body .token.tag,:root[theme] [theme=light] .markdown-body .token.boolean,:root[theme] [theme=light] .markdown-body .token.constant,:root[theme] [theme=light] .markdown-body .token.deleted,:root[theme] [theme=light] .markdown-body .token.number,:root[theme] [theme=light] .markdown-body .token.property,:root[theme] [theme=light] .markdown-body .token.symbol,:root[theme] [theme=light] .markdown-body .token.tag{color:#905}:root[theme=light] :not([theme])>*>.markdown-body .token.attr-name,:root[theme=light] :not([theme])>*>.markdown-body .token.builtin,:root[theme=light] :not([theme])>*>.markdown-body .token.char,:root[theme=light] :not([theme])>*>.markdown-body .token.inserted,:root[theme=light] :not([theme])>*>.markdown-body .token.selector,:root[theme=light] :not([theme])>*>.markdown-body .token.string,:root[theme] [theme=light] .markdown-body .token.attr-name,:root[theme] [theme=light] .markdown-body .token.builtin,:root[theme] [theme=light] .markdown-body .token.char,:root[theme] [theme=light] .markdown-body .token.inserted,:root[theme] [theme=light] .markdown-body .token.selector,:root[theme] [theme=light] .markdown-body .token.string{color:#690}:root[theme=light] :not([theme])>*>.markdown-body .language-css .token.string,:root[theme=light] :not([theme])>*>.markdown-body .style .token.string,:root[theme=light] :not([theme])>*>.markdown-body .token.entity,:root[theme=light] :not([theme])>*>.markdown-body .token.operator,:root[theme=light] :not([theme])>*>.markdown-body .token.url,:root[theme] [theme=light] .markdown-body .language-css .token.string,:root[theme] [theme=light] .markdown-body .style .token.string,:root[theme] [theme=light] .markdown-body .token.entity,:root[theme] [theme=light] .markdown-body .token.operator,:root[theme] [theme=light] .markdown-body .token.url{background:#ffffff80;color:#9a6e3a}:root[theme=light] :not([theme])>*>.markdown-body .token.atrule,:root[theme=light] :not([theme])>*>.markdown-body .token.attr-value,:root[theme=light] :not([theme])>*>.markdown-body .token.keyword,:root[theme] [theme=light] .markdown-body .token.atrule,:root[theme] [theme=light] .markdown-body .token.attr-value,:root[theme] [theme=light] .markdown-body .token.keyword{color:#07a}:root[theme=light] :not([theme])>*>.markdown-body .token.class-name,:root[theme=light] :not([theme])>*>.markdown-body .token.function,:root[theme] [theme=light] .markdown-body .token.class-name,:root[theme] [theme=light] .markdown-body .token.function{color:#dd4a68}:root[theme=light] :not([theme])>*>.markdown-body .token.important,:root[theme=light] :not([theme])>*>.markdown-body .token.regex,:root[theme=light] :not([theme])>*>.markdown-body .token.variable,:root[theme] [theme=light] .markdown-body .token.important,:root[theme] [theme=light] .markdown-body .token.regex,:root[theme] [theme=light] .markdown-body .token.variable{color:#e90}:root[theme=light] :not([theme])>*>.markdown-body .token.bold,:root[theme=light] :not([theme])>*>.markdown-body .token.important,:root[theme] [theme=light] .markdown-body .token.bold,:root[theme] [theme=light] .markdown-body .token.important{font-weight:700}:root[theme=light] :not([theme])>*>.markdown-body .token.italic,:root[theme] [theme=light] .markdown-body .token.italic{font-style:italic}:root[theme=light] :not([theme])>*>.markdown-body .token.entity,:root[theme] [theme=light] .markdown-body .token.entity{cursor:help}@media print{:root[theme=light] :not([theme])>*>.markdown-body code[class*=language-],:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=light] .markdown-body code[class*=language-],:root[theme] [theme=light] .markdown-body pre[class*=language-]{text-shadow:none}}.markdown-body{word-wrap:break-word;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;font-size:16px;line-height:1.5}.markdown-body:after,.markdown-body:before{content:"";display:table}.markdown-body:after{clear:both}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:#c00}.markdown-body .anchor{float:left;line-height:1;margin-left:-20px;padding-right:4px}.markdown-body .anchor:focus{outline:none}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-bottom:16px;margin-top:0}.markdown-body hr{background-color:#e7e7e7;border:0;height:.25em;margin:24px 0;padding:0}.markdown-body blockquote{border-left:.25em solid #ddd;color:#777;font-size:16px;padding:0 1em}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body kbd,.popover kbd{background-color:#fcfcfc;border:1px solid;border-color:#ccc #ccc #bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb;color:#555;display:inline-block;font-size:11px;line-height:10px;padding:3px 5px;vertical-align:middle}.markdown-body .loweralpha{list-style-type:lower-alpha}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{font-weight:600;line-height:1.25;margin-bottom:16px;margin-top:24px}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#000;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit}.markdown-body h1{font-size:2em}.markdown-body h1,.markdown-body h2{border-bottom:1px solid #eee;padding-bottom:.3em}.markdown-body h2{font-size:1.5em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{color:#777;font-size:.85em}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol.no-list,.markdown-body ul.no-list{list-style-type:none;padding:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-bottom:0;margin-top:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{padding-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{font-size:1em;font-style:italic;font-weight:700;margin-top:16px;padding:0}.markdown-body dl dd{margin-bottom:16px;padding:0 16px}.markdown-body table{display:block;overflow:auto;width:100%;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{border:1px solid #ddd}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{background-color:#fff;box-sizing:initial;max-width:100%}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{background-color:initial;max-width:none;vertical-align:text-top}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{border:1px solid #ddd;display:block;float:left;margin:13px 0 0;overflow:hidden;padding:7px;width:auto}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{clear:both;color:#333;display:block;padding:5px 0 0}.markdown-body span.align-center{clear:both;display:block;overflow:hidden}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{clear:both;display:block;overflow:hidden}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{background-color:#0000000a;border-radius:3px;font-size:85%;margin:0;padding:.2em 0}.markdown-body code:after,.markdown-body code:before,.markdown-body tt:after,.markdown-body tt:before{content:"\00a0";letter-spacing:-.2em}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre{word-wrap:normal}.markdown-body pre>code{background:#0000;border:0;font-size:100%;margin:0;padding:0;white-space:pre;word-break:normal}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{border-radius:3px;font-size:85%;line-height:1.45;overflow:auto}.markdown-body:not(.next-editor) pre{padding:16px}.markdown-body pre code,.markdown-body pre tt{word-wrap:normal;background-color:initial;border:0;display:inline;line-height:inherit;margin:0;max-width:auto;overflow:visible;padding:0}.markdown-body pre code:after,.markdown-body pre code:before,.markdown-body pre tt:after,.markdown-body pre tt:before{content:normal}.markdown-body .csv-data td,.markdown-body .csv-data th{font-size:12px;line-height:1;overflow:hidden;padding:5px;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-line-num{background:#fff;border:0;padding:10px 8px 9px;text-align:right}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{background:#f8f8f8;border-top:0;font-weight:700}.news .alert .markdown-body blockquote{border:0;padding:0 0 0 40px}.activity-tab .news .alert .commits,.activity-tab .news .markdown-body blockquote{padding-left:0}.task-list-item{list-style-type:none}.task-list-item label{font-weight:400}.task-list-item.enabled label{cursor:pointer}.task-list-item+.task-list-item{margin-top:3px}.task-list-item-checkbox{cursor:default!important;float:left;margin:.31em 0 .2em -1.3em!important;vertical-align:middle}.markdown-alert{border-left-style:solid;border-left-width:4px;color:inherit;margin-bottom:16px;padding:8px 16px}.markdown-alert .markdown-alert-title{align-items:center;display:flex;font-weight:500;line-height:1;white-space:break-spaces}.markdown-body .markdown-alert>*{margin-bottom:0;margin-top:16px}.markdown-body .markdown-alert .selection-popover,.markdown-body .markdown-alert>:first-child{margin-top:0}.markdown-alert.markdown-alert-note{border-left-color:var(--hmd-tw-state-info-default)}.markdown-alert.markdown-alert-note .markdown-alert-title{fill:currentColor;color:var(--hmd-tw-state-info-text)}.markdown-alert.markdown-alert-tip{border-left-color:var(--hmd-tw-state-success-default)}.markdown-alert.markdown-alert-tip .markdown-alert-title{fill:currentColor;color:var(--hmd-tw-state-success-text)}.markdown-alert.markdown-alert-important{border-left-color:var(--hmd-tw-border-primary-default)}.markdown-alert.markdown-alert-important .markdown-alert-title{fill:currentColor;color:var(--hmd-tw-text-primary)}.markdown-alert.markdown-alert-warning{border-left-color:var(--hmd-tw-state-warning-default)}.markdown-alert.markdown-alert-warning .markdown-alert-title{fill:currentColor;color:var(--hmd-tw-state-warning-text)}.markdown-alert.markdown-alert-caution{border-left-color:var(--hmd-tw-state-danger-default)}.markdown-alert.markdown-alert-caution .markdown-alert-title{fill:currentColor;color:var(--hmd-tw-state-danger-text)}:root[theme=dark] :not([theme])>*>.markdown-body,:root[theme] [theme=dark] .markdown-body{color:#d4d4d8}:root[theme=dark] :not([theme])>*>.markdown-body h1,:root[theme=dark] :not([theme])>*>.markdown-body h2,:root[theme] [theme=dark] .markdown-body h1,:root[theme] [theme=dark] .markdown-body h2{border-bottom-color:#52525b}:root[theme=dark] :not([theme])>*>.markdown-body h6,:root[theme] [theme=dark] .markdown-body h6{color:#a1a1aa}:root[theme=dark] :not([theme])>*>.markdown-body details,:root[theme] [theme=dark] .markdown-body details{background-color:#303036;color:#d4d4d8}:root[theme=dark] :not([theme])>*>.markdown-body details summary::marker:first-child,:root[theme] [theme=dark] .markdown-body details summary::marker:first-child{color:#d4d4d8}:root[theme=dark] :not([theme])>*>.markdown-body details:hover,:root[theme] [theme=dark] .markdown-body details:hover{background:#303036}:root[theme=dark] :not([theme])>*>.markdown-body details code,:root[theme=dark] :not([theme])>*>.markdown-body details[open]:hover,:root[theme] [theme=dark] .markdown-body details code,:root[theme] [theme=dark] .markdown-body details[open]:hover{background-color:#303036}:root[theme=dark] :not([theme])>*>.markdown-body hr,:root[theme] [theme=dark] .markdown-body hr{background-color:#52525b}:root[theme=dark] :not([theme])>*>.markdown-body blockquote,:root[theme] [theme=dark] .markdown-body blockquote{border-left-color:#71717a;color:#a1a1aa}:root[theme=dark] :not([theme])>*>.markdown-body blockquote a span,:root[theme] [theme=dark] .markdown-body blockquote a span{color:#9894f9}:root[theme=dark] :not([theme])>*>.markdown-body a.mention-anchor.user-card-popover,:root[theme] [theme=dark] .markdown-body a.mention-anchor.user-card-popover{background-color:#453aff26;color:#9894f9}:root[theme=dark] :not([theme])>*>.markdown-body ::selection,:root[theme] [theme=dark] .markdown-body ::selection{background-color:#453aff99}:root[theme=dark] :not([theme])>*>.markdown-body .alert.alert-info,:root[theme] [theme=dark] .markdown-body .alert.alert-info{background-color:#38bdf81a;border-left-color:#0ea5e9;color:#38bdf8}:root[theme=dark] :not([theme])>*>.markdown-body .alert.alert-warning,:root[theme] [theme=dark] .markdown-body .alert.alert-warning{background-color:#fbbf241a;border-left-color:#f59e0b;color:#f59e0b}:root[theme=dark] :not([theme])>*>.markdown-body .alert.alert-success,:root[theme] [theme=dark] .markdown-body .alert.alert-success{background-color:#6db19d26;border-left-color:#55b685;color:#6db19d}:root[theme=dark] :not([theme])>*>.markdown-body .alert.alert-danger,:root[theme] [theme=dark] .markdown-body .alert.alert-danger{background-color:#ef444433;border-left-color:#ef4444;color:#f87171}:root[theme=dark] :not([theme])>*>.markdown-body .mark,:root[theme=dark] :not([theme])>*>.markdown-body mark,:root[theme] [theme=dark] .markdown-body .mark,:root[theme] [theme=dark] .markdown-body mark{background-color:#fbbf241a;color:#f59e0b}:root[theme=dark] :not([theme])>*>.markdown-body .mark span,:root[theme=dark] :not([theme])>*>.markdown-body mark span,:root[theme] [theme=dark] .markdown-body .mark span,:root[theme] [theme=dark] .markdown-body mark span{color:#fbbf24}:root[theme=dark] :not([theme])>*>.markdown-body .highlight pre,:root[theme=dark] :not([theme])>*>.markdown-body pre,:root[theme] [theme=dark] .markdown-body .highlight pre,:root[theme] [theme=dark] .markdown-body pre{background-color:#303036;color:#a1a1aa}:root[theme=dark] :not([theme])>*>.markdown-body .style .token.string,:root[theme=dark] :not([theme])>*>.markdown-body .token.entity,:root[theme=dark] :not([theme])>*>.markdown-body .token.operator,:root[theme=dark] :not([theme])>*>.markdown-body .token.url,:root[theme=dark] :not([theme])>*>.markdown-body.language-css,:root[theme=dark] :not([theme])>*>.markdown-body.token.string,:root[theme] [theme=dark] .markdown-body .style .token.string,:root[theme] [theme=dark] .markdown-body .token.entity,:root[theme] [theme=dark] .markdown-body .token.operator,:root[theme] [theme=dark] .markdown-body .token.url,:root[theme] [theme=dark] .markdown-body.language-css,:root[theme] [theme=dark] .markdown-body.token.string{background:none}:root[theme=dark] :not([theme])>*>.markdown-body :not(pre)>code,:root[theme] [theme=dark] .markdown-body :not(pre)>code{background-color:#3f3f46}:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-tag,:root[theme] [theme=dark] .markdown-body code .hljs-tag{color:#d4d4d8}:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-keyword,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-selector-tag,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-type,:root[theme=dark] :not([theme])>*>.markdown-body code .token.boolean,:root[theme=dark] :not([theme])>*>.markdown-body code .token.constant,:root[theme=dark] :not([theme])>*>.markdown-body code .token.deleted,:root[theme=dark] :not([theme])>*>.markdown-body code .token.number,:root[theme=dark] :not([theme])>*>.markdown-body code .token.property,:root[theme=dark] :not([theme])>*>.markdown-body code .token.symbol,:root[theme=dark] :not([theme])>*>.markdown-body code .token.tag,:root[theme] [theme=dark] .markdown-body code .hljs-keyword,:root[theme] [theme=dark] .markdown-body code .hljs-selector-tag,:root[theme] [theme=dark] .markdown-body code .hljs-type,:root[theme] [theme=dark] .markdown-body code .token.boolean,:root[theme] [theme=dark] .markdown-body code .token.constant,:root[theme] [theme=dark] .markdown-body code .token.deleted,:root[theme] [theme=dark] .markdown-body code .token.number,:root[theme] [theme=dark] .markdown-body code .token.property,:root[theme] [theme=dark] .markdown-body code .token.symbol,:root[theme] [theme=dark] .markdown-body code .token.tag{color:#ff70b4}:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-attribute,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-bullet,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-literal,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-number,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-symbol,:root[theme=dark] :not([theme])>*>.markdown-body code .token.atrule,:root[theme=dark] :not([theme])>*>.markdown-body code .token.attr-value,:root[theme=dark] :not([theme])>*>.markdown-body code .token.keyword,:root[theme] [theme=dark] .markdown-body code .hljs-attribute,:root[theme] [theme=dark] .markdown-body code .hljs-bullet,:root[theme] [theme=dark] .markdown-body code .hljs-literal,:root[theme] [theme=dark] .markdown-body code .hljs-number,:root[theme] [theme=dark] .markdown-body code .hljs-symbol,:root[theme] [theme=dark] .markdown-body code .token.atrule,:root[theme] [theme=dark] .markdown-body code .token.attr-value,:root[theme] [theme=dark] .markdown-body code .token.keyword{color:#9894f9}:root[theme=dark] :not([theme])>*>.markdown-body pre.plugin-rendered,:root[theme] [theme=dark] .markdown-body pre.plugin-rendered{background-color:#fff;color:#000}:root[theme=dark] :not([theme])>*>.markdown-body table,:root[theme] [theme=dark] .markdown-body table{border-color:#52525b}:root[theme=dark] :not([theme])>*>.markdown-body table thead tr,:root[theme] [theme=dark] .markdown-body table thead tr{background-color:#303036;border-bottom-color:#52525b}:root[theme=dark] :not([theme])>*>.markdown-body table td,:root[theme=dark] :not([theme])>*>.markdown-body table th,:root[theme] [theme=dark] .markdown-body table td,:root[theme] [theme=dark] .markdown-body table th{border-left-color:#52525b;border-top-color:#52525b}:root[theme=dark] :not([theme])>*>.markdown-body table tbody tr,:root[theme=dark] :not([theme])>*>.markdown-body table tr:nth-child(2n),:root[theme] [theme=dark] .markdown-body table tbody tr,:root[theme] [theme=dark] .markdown-body table tr:nth-child(2n){background-color:#27272a}:root[theme=light] :not([theme])>*>.markdown-body,:root[theme] [theme=light] .markdown-body{color:#3f3f46}:root[theme=light] :not([theme])>*>.markdown-body h1,:root[theme=light] :not([theme])>*>.markdown-body h2,:root[theme] [theme=light] .markdown-body h1,:root[theme] [theme=light] .markdown-body h2{border-bottom-color:#e4e4e7}:root[theme=light] :not([theme])>*>.markdown-body h6,:root[theme] [theme=light] .markdown-body h6{color:#71717a}:root[theme=light] :not([theme])>*>.markdown-body iframe,:root[theme] [theme=light] .markdown-body iframe{border:1px solid #e4e4e7;box-sizing:border-box}:root[theme=light] :not([theme])>*>.markdown-body details,:root[theme] [theme=light] .markdown-body details{background-color:#f4f4f5}:root[theme=light] :not([theme])>*>.markdown-body details:hover,:root[theme] [theme=light] .markdown-body details:hover{background:#e4e4e7}:root[theme=light] :not([theme])>*>.markdown-body details[open]:hover,:root[theme] [theme=light] .markdown-body details[open]:hover{background-color:#f4f4f5}:root[theme=light] :not([theme])>*>.markdown-body details code,:root[theme] [theme=light] .markdown-body details code{background-color:#e4e4e7}:root[theme=light] :not([theme])>*>.markdown-body hr,:root[theme] [theme=light] .markdown-body hr{background-color:#d4d4d8}:root[theme=light] :not([theme])>*>.markdown-body blockquote,:root[theme] [theme=light] .markdown-body blockquote{border-left-color:#e4e4e7;color:#71717a}:root[theme=light] :not([theme])>*>.markdown-body blockquote a span,:root[theme] [theme=light] .markdown-body blockquote a span{color:#564dff}:root[theme=light] :not([theme])>*>.markdown-body a.mention-anchor.user-card-popover,:root[theme] [theme=light] .markdown-body a.mention-anchor.user-card-popover{background-color:#ecebfe;color:#564dff}:root[theme=light] :not([theme])>*>.markdown-body ::selection,:root[theme] [theme=light] .markdown-body ::selection{background-color:#cccafc}:root[theme=light] :not([theme])>*>.markdown-body .alert.alert-info,:root[theme] [theme=light] .markdown-body .alert.alert-info{background-color:#e0f2fe;border-left-color:#0284c7;color:#0284c7}:root[theme=light] :not([theme])>*>.markdown-body .alert.alert-warning,:root[theme] [theme=light] .markdown-body .alert.alert-warning{background-color:#fef3c799;border-left-color:#f59e0b;color:#f59e0b}:root[theme=light] :not([theme])>*>.markdown-body .alert.alert-success,:root[theme] [theme=light] .markdown-body .alert.alert-success{background-color:#d9f9e5;border-left-color:#43946c;color:#43946c}:root[theme=light] :not([theme])>*>.markdown-body .alert.alert-danger,:root[theme] [theme=light] .markdown-body .alert.alert-danger{background-color:#fee2e299;border-left-color:#ef4444;color:#ef4444}:root[theme=light] :not([theme])>*>.markdown-body .mark,:root[theme=light] :not([theme])>*>.markdown-body mark,:root[theme] [theme=light] .markdown-body .mark,:root[theme] [theme=light] .markdown-body mark{background-color:#fef3c799;color:#f59e0b}:root[theme=light] :not([theme])>*>.markdown-body .mark span,:root[theme=light] :not([theme])>*>.markdown-body mark span,:root[theme] [theme=light] .markdown-body .mark span,:root[theme] [theme=light] .markdown-body mark span{color:#f59e0b}:root[theme=light] :not([theme])>*>.markdown-body .highlight pre,:root[theme=light] :not([theme])>*>.markdown-body pre,:root[theme] [theme=light] .markdown-body .highlight pre,:root[theme] [theme=light] .markdown-body pre{background-color:#f4f4f5}:root[theme=light] :not([theme])>*>.markdown-body pre.plugin-rendered,:root[theme] [theme=light] .markdown-body pre.plugin-rendered{background-color:inherit;color:inherit}:root[theme=light] :not([theme])>*>.markdown-body :not(pre)>code,:root[theme] [theme=light] .markdown-body :not(pre)>code{background-color:#0000000a}:root[theme=light] :not([theme])>*>.markdown-body table,:root[theme] [theme=light] .markdown-body table{border-color:#e4e4e7}:root[theme=light] :not([theme])>*>.markdown-body table thead tr,:root[theme] [theme=light] .markdown-body table thead tr{background-color:#f4f4f5;border-bottom-color:#d4d4d8}:root[theme=light] :not([theme])>*>.markdown-body table td,:root[theme=light] :not([theme])>*>.markdown-body table th,:root[theme] [theme=light] .markdown-body table td,:root[theme] [theme=light] .markdown-body table th{border-left-color:#e4e4e7;border-top-color:#e4e4e7}:root[theme=light] :not([theme])>*>.markdown-body table tbody tr,:root[theme=light] :not([theme])>*>.markdown-body table tr:nth-child(2n),:root[theme] [theme=light] .markdown-body table tbody tr,:root[theme] [theme=light] .markdown-body table tr:nth-child(2n){background-color:#fdfdfd}.markdown-body{font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;max-width:758px;overflow:visible!important;padding-bottom:40px;padding-top:40px;position:relative}.markdown-body>*{max-width:100%}.markdown-body .alert a,.markdown-body a{color:var(--hmd-tw-link-text-default)}.markdown-body .alert a:focus,.markdown-body .alert a:hover,.markdown-body a:focus,.markdown-body a:hover{color:var(--hmd-tw-link-text-hover)}.markdown-body .alert a:hover,.markdown-body a:hover{text-decoration-thickness:2px;text-underline-offset:4px}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5{font-family:Readex Pro,-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;font-weight:700}.markdown-body h1,.markdown-body h2{border-bottom:1px solid}.markdown-body iframe,.markdown-body img{background-color:initial;border-radius:6px;margin:.5rem 0}.markdown-body iframe{max-width:100%;width:728px}.markdown-body details{border-radius:4px;margin-bottom:.5rem;padding:.5rem 1rem}.markdown-body details:hover{transition:all .1s}.markdown-body details summary+p{margin-top:.5rem}.markdown-body details p:last-child{margin-bottom:0}.markdown-body hr{height:2px}.markdown-body img.emoji{border:none;height:20px;vertical-align:middle;width:20px}.markdown-body li small{color:#a1a1aa}.markdown-body blockquote{border-left:3px solid}.markdown-body blockquote .small,.markdown-body blockquote small,.markdown-body li small{display:initial;font-size:85%}.markdown-body a.mention-anchor:before{content:"";margin-right:0}.markdown-body a.mention-anchor.user-card-popover{border-radius:4px;padding:1px 4px}.markdown-body .alert{border:none;border-radius:4px;margin-top:10px}.markdown-body .alert h2,.markdown-body .alert h3,.markdown-body .alert h4,.markdown-body .alert h5,.markdown-body .alert h6{margin-top:0}.markdown-body .alert h2{border:none}.markdown-body .alert.alert-danger,.markdown-body .alert.alert-info,.markdown-body .alert.alert-success,.markdown-body .alert.alert-warning{border-left:3px solid}.markdown-body .highlight pre,.markdown-body .mark,.markdown-body mark,.markdown-body pre{border-radius:4px}.markdown-body pre.abc,.markdown-body pre.flow-chart,.markdown-body pre.fretboard,.markdown-body pre.graphviz,.markdown-body pre.mermaid,.markdown-body pre.sequence-diagram,.markdown-body pre.vega-embed{border-radius:4px;max-width:100%;overflow:auto}.markdown-body .code-block-wrapper{border-radius:4px;outline-color:#0000;outline-style:solid;outline-width:1px;position:relative}.markdown-body .code-block-wrapper .code-toolbar{--tw-translate-y:-100%;--tw-shadow:0 3px 15px 0 #00000026;--tw-shadow-colored:0 3px 15px 0 var(--tw-shadow-color);background-color:var(--hmd-tw-element-bg-default);border-color:var(--hmd-tw-border-default);border-radius:4px;border-style:solid;border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);opacity:0;position:absolute;right:0;top:-1px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);visibility:hidden}.markdown-body .code-block-wrapper:hover{outline-color:var(--hmd-tw-border-primary-default);transition-duration:.15s;transition-property:outline-color;transition-timing-function:cubic-bezier(.4,0,.2,1)}.markdown-body .code-block-wrapper:hover .code-toolbar{opacity:1;visibility:visible}.markdown-body table{border:1px solid;border-radius:4px;width:fit-content}.markdown-body table thead tr{border-bottom:1px solid;border-top:none}.markdown-body table tbody tr,.markdown-body table thead tr th{border-top:none}.markdown-body table tbody tr td:first-child,.markdown-body table thead,.markdown-body table thead th:first-child{border-left:none}.markdown-body table td,.markdown-body table th{border:1px solid;border-bottom:none;border-right:none;padding:6px 13px}.markdown-body.next-editor{overflow-x:hidden!important}.markdown-body pre{border:inherit}.markdown-body code{color:inherit}html[lang^=ja] .markdown-body code code,html[lang^=ja] .markdown-body code kbd,html[lang^=ja] .markdown-body code pre{font-family:Source Code Pro,Consolas,monaco,Meiryo,ＭＳ ゴシック,MS Gothic,monospace}html[lang=zh-tw] .markdown-body code code,html[lang=zh-tw] .markdown-body code kbd,html[lang=zh-tw] .markdown-body code pre{font-family:Source Code Pro,Consolas,monaco,Microsoft JhengHei,微軟正黑,monospace}html[lang=zh-cn] .markdown-body code code,html[lang=zh-cn] .markdown-body code kbd,html[lang=zh-cn] .markdown-body code pre{font-family:Source Code Pro,Consolas,monaco,Microsoft YaHei,微软雅黑,monospace}html .markdown-body code[lang^=ja] code,html .markdown-body code[lang^=ja] kbd,html .markdown-body code[lang^=ja] pre{font-family:Source Code Pro,Consolas,monaco,Meiryo,ＭＳ ゴシック,MS Gothic,monospace}html .markdown-body code[lang=zh-tw] code,html .markdown-body code[lang=zh-tw] kbd,html .markdown-body code[lang=zh-tw] pre{font-family:Source Code Pro,Consolas,monaco,Microsoft JhengHei,微軟正黑,monospace}html .markdown-body code[lang=zh-cn] code,html .markdown-body code[lang=zh-cn] kbd,html .markdown-body code[lang=zh-cn] pre{font-family:Source Code Pro,Consolas,monaco,Microsoft YaHei,微软雅黑,monospace}.markdown-body pre code .wrapper{display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}.markdown-body pre code .gutter{float:left;overflow:hidden;-webkit-user-select:none;user-select:none}.markdown-body pre code .gutter.linenumber{border-right:2px solid #766df8;box-sizing:initial;color:#a1a1aa;cursor:default;display:inline-block;min-width:20px;padding:0 8px 0 0;position:relative;text-align:right;z-index:4}.markdown-body pre code .gutter.linenumber>span:before{content:attr(data-linenumber)}.markdown-body pre code .code{float:left;margin:0 0 0 16px}.markdown-body .gist .line-numbers{border-bottom:none;border-left:none;border-top:none}.markdown-body .gist .line-data{border:none}.markdown-body .gist table{border-collapse:inherit!important;border-spacing:0}.markdown-body code[data-gist-id]{background:none;padding:0}.markdown-body code[data-gist-id]:after,.markdown-body code[data-gist-id]:before{content:""}.markdown-body code[data-gist-id] .blob-num{border:unset}.markdown-body code[data-gist-id] table{margin-bottom:unset;overflow:unset}.markdown-body code[data-gist-id] table tr{background:unset}.markdown-body[dir=rtl] pre{direction:ltr}.markdown-body[dir=rtl] code{direction:ltr;unicode-bidi:embed}.markdown-body .alert{display:flex;flex-direction:column;gap:16px}.markdown-body .alert>*{margin:0}.markdown-body pre.abc,.markdown-body pre.flow-chart,.markdown-body pre.graphviz,.markdown-body pre.mermaid,.markdown-body pre.sequence-diagram,.markdown-body pre.vega{background-color:inherit;border-radius:0;overflow:visible;text-align:center;white-space:inherit}.markdown-body pre.abc>code,.markdown-body pre.flow-chart>code,.markdown-body pre.graphviz>code,.markdown-body pre.mermaid>code,.markdown-body pre.sequence-diagram>code,.markdown-body pre.vega>code{text-align:left}.markdown-body pre.abc>svg,.markdown-body pre.flow-chart>svg,.markdown-body pre.graphviz>svg,.markdown-body pre.mermaid>svg,.markdown-body pre.sequence-diagram>svg,.markdown-body pre.vega>svg{height:100%;max-width:100%}.markdown-body pre>code.wrap{word-wrap:break-word;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap}.markdown-body pre.pseudocode{white-space-collapse:collapse}.markdown-body summary{display:list-item}.markdown-body summary:focus{outline:none}.markdown-body details summary{cursor:pointer}.markdown-body details:not([open])>:not(summary){display:none}.markdown-body figure{margin:1em 40px}.markdown-body .mark,.markdown-body mark{background-color:#fff1a7}:root[theme] .markdown-body{line-height:1.75}:root[theme] .markdown-body ::marker,:root[theme] .markdown-body code{color:var(--hmd-tw-text-default)}:root[theme] .markdown-body h1,:root[theme] .markdown-body h2,:root[theme] .markdown-body h3,:root[theme] .markdown-body h4,:root[theme] .markdown-body h5,:root[theme] .markdown-body h6{overflow:visible}:root[theme] .markdown-body h1 .octicon-link,:root[theme] .markdown-body h2 .octicon-link,:root[theme] .markdown-body h3 .octicon-link,:root[theme] .markdown-body h4 .octicon-link,:root[theme] .markdown-body h5 .octicon-link,:root[theme] .markdown-body h6 .octicon-link{color:var(--hmd-tw-text-subtle)}:root[theme] .markdown-body .anchor{left:0;margin-left:0;position:absolute}:root[theme] .markdown-body .gist table{border-color:inherit}:root[theme] .markdown-body .gist table thead tr{background-color:inherit;border-bottom-color:inherit}:root[theme] .markdown-body .gist table td,:root[theme] .markdown-body .gist table th{border-left-color:inherit;border-top-color:inherit}:root[theme] .markdown-body .gist table tbody tr,:root[theme] .markdown-body .gist table tr:nth-child(2n){background-color:inherit}:root[theme] .markdown-body ol ol,:root[theme] .markdown-body ol ul,:root[theme] .markdown-body ul ol,:root[theme] .markdown-body ul ul{margin-bottom:12px;margin-top:6px}@media (max-width:767px){.markdown-body h1{font-size:1.6em}.markdown-body h2{font-size:1.4em}.markdown-body h3{font-size:1.125em}}.vimeo,.youtube{background-color:#000;background-position:50%;background-repeat:no-repeat;background-size:contain;cursor:pointer;display:table;overflow:hidden;text-align:center}.vimeo,.youtube{position:relative;width:100%}.youtube{padding-bottom:56.25%}.vimeo img{object-fit:contain;width:100%;z-index:0}.youtube img{object-fit:cover;z-index:0}.vimeo iframe,.youtube iframe,.youtube img{height:100%;left:0;position:absolute;top:0;width:100%}.vimeo iframe,.youtube iframe{vertical-align:middle;z-index:1}.vimeo .icon,.youtube .icon{color:#fff;height:auto;left:50%;opacity:.3;position:absolute;top:50%;transform:translate(-50%,-50%);transition:opacity .2s;width:auto;z-index:0}.vimeo:hover .icon,.youtube:hover .icon{opacity:.6;transition:opacity .2s}.slideshare .inner,.speakerdeck .inner{position:relative;width:100%}.slideshare .inner iframe,.speakerdeck .inner iframe{bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.figma{display:table;padding-bottom:56.25%;position:relative;width:100%}.figma iframe{border:1px solid #eee;bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.markmap-container{height:300px}.markmap-container>svg{height:100%;width:100%}.MJX_Assistive_MathML{display:none}#MathJax_Message{z-index:1000!important}.ui-infobar{color:var(--hmd-tw-text-default);font-size:14px;margin:25px auto -25px;max-width:760px;position:relative;z-index:2}.ui-infobar .ui-user-icon.small{height:18px;margin:2px;vertical-align:top;width:18px}.toc .invisable-node{list-style-type:none}.ui-toc{bottom:20px;position:fixed;z-index:998}.ui-toc.both-mode{margin-left:2px}.ui-toc.both-mode .ui-toc-label{border-bottom-left-radius:0;border-top-left-radius:0;height:40px;padding:10px 4px}:root[theme=light] :not([theme])>*>.ui-toc .ui-toc-label,:root[theme] [theme=light] .ui-toc-label{background-color:#fdfdfd;border-color:#d4d4d8;color:#a1a1aa}:root[theme=light] :not([theme])>*>.ui-toc .ui-toc-label:active,:root[theme=light] :not([theme])>*>.ui-toc .ui-toc-label:hover,:root[theme] [theme=light] .ui-toc-label:active,:root[theme] [theme=light] .ui-toc-label:hover{background-color:#f4f4f5;border-color:#d4d4d8;color:#a1a1aa}:root[theme=dark] :not([theme])>*>.ui-toc .ui-toc-label,:root[theme=dark] :not([theme])>*>.ui-toc .ui-toc-label:active,:root[theme=dark] :not([theme])>*>.ui-toc .ui-toc-label:hover,:root[theme] [theme=dark] .ui-toc-label,:root[theme] [theme=dark] .ui-toc-label:active,:root[theme] [theme=dark] .ui-toc-label:hover{background-color:#303036;border-color:#52525b;color:#a1a1aa}:root[theme=dark] :not([theme])>*>.ui-toc.both-mode .ui-toc-label,:root[theme] [theme=dark] .ui-toc.both-mode .ui-toc-label{background-color:#303036;border-color:#3f3f46;color:#d4d4d8}:root[theme=dark] :not([theme])>*>.ui-toc.both-mode .ui-toc-label:hover,:root[theme] [theme=dark] .ui-toc.both-mode .ui-toc-label:hover{background-color:#52525b}.ui-toc-label{border:1px solid;transition:opacity .2s}.ui-toc .open .ui-toc-label,.ui-toc-label:hover{opacity:1;transition:opacity .2s}.ui-toc-dropdown{letter-spacing:normal;margin-bottom:20px;margin-top:20px;max-height:70vh;max-width:45vw;overflow:auto;padding-left:10px;padding-right:10px;text-align:inherit;width:25vw}.ui-toc-dropdown.dropdown-menu{box-shadow:0 3px 15px 0 #00000026}.ui-toc-dropdown>.toc{max-height:calc(70vh - 100px);overflow:auto}.ui-toc-dropdown[dir=rtl] .nav{letter-spacing:.0029em;padding-right:0}.ui-toc-dropdown a{overflow:hidden;text-overflow:ellipsis;white-space:pre}.ui-toc-dropdown .nav>li>a{color:var(--hmd-tw-text-subtle);display:block;font-size:12px;font-weight:500;line-height:16px;padding:4px 20px}.ui-toc-dropdown .nav>li:first-child:last-child>ul,.ui-toc-dropdown .toc.expand ul{display:block}.ui-toc-dropdown .nav>li>a:focus,.ui-toc-dropdown .nav>li>a:hover{background-color:initial;border-color:var(--hmd-tw-border-bold);border-style:solid;border-width:0 0 0 1px;color:#000;color:var(--hmd-tw-text-emphasize);padding-left:19px;text-decoration:none}.ui-toc-dropdown[dir=rtl] .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav>li>a:hover{border-left:none;border-right:1px solid #000;padding-right:19px}.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a{background-color:initial;border-color:var(--hmd-tw-border-bold);border-style:solid;border-width:0 0 0 2px;color:var(--hmd-tw-text-emphasize);font-weight:600;padding-left:18px}.ui-toc-dropdown[dir=rtl] .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav>.active>a{border-width:0 2px 0 medium;border-left:0;border-color:var(--hmd-tw-border-bold);border-style:solid;padding-right:18px}.ui-toc-dropdown .nav .nav{display:none;padding-bottom:10px}.ui-toc-dropdown .nav>.active>ul{display:block}.ui-toc-dropdown .nav .nav>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:30px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a{padding-right:30px}.ui-toc-dropdown .nav .nav>li>ul>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:40px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a{padding-right:40px}.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover{padding-left:29px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:hover{padding-right:29px}.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover{padding-left:39px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:hover{padding-right:39px}.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a{font-weight:500;padding-left:28px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>a{padding-right:28px}.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a{font-weight:500;padding-left:38px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active>a{padding-right:38px}.ui-affix-toc{max-height:70vh;max-width:15vw;overflow:auto;position:fixed;top:0}.back-to-top,.expand-toggle,.go-to-bottom{color:var(--hmd-tw-text-subtle);display:block;font-size:12px;font-weight:500;line-height:16px;margin-left:10px;margin-top:10px;padding:2px 10px}.back-to-top:focus,.back-to-top:hover,.expand-toggle:focus,.expand-toggle:hover,.go-to-bottom:focus,.go-to-bottom:hover{color:var(--hmd-tw-text-primary);text-decoration:none}.back-to-top,.go-to-bottom{margin-top:0}.ui-user-icon{background-position:50%;background-repeat:no-repeat;background-size:cover;border-radius:50%;display:block;height:20px;margin-bottom:2px;margin-right:5px;margin-top:2px;width:20px}.ui-user-icon.small{display:inline-block;height:18px;margin:0 0 .2em;vertical-align:middle;width:18px}.ui-infobar>small>span{line-height:22px}.ui-infobar>small .dropdown{display:inline-block}.ui-infobar>small .dropdown a:focus,.ui-infobar>small .dropdown a:hover{text-decoration:none}.ui-more-info{cursor:pointer;vertical-align:middle}.ui-connectedGithub{line-height:23px;white-space:nowrap}.ui-connectedGithub a.file-path{text-decoration:none}.ui-connectedGithub a.file-path:active,.ui-connectedGithub a.file-path:hover{text-decoration:underline}.unselectable{-webkit-user-select:none;-o-user-select:none;user-select:none}.selectable{-webkit-user-select:text;-o-user-select:text;user-select:text}.inline-spoiler-section{cursor:pointer}.inline-spoiler-section .spoiler-text{background-color:#333;border-radius:2px}.inline-spoiler-section .spoiler-text>*{opacity:0}.inline-spoiler-section .spoiler-img{filter:blur(10px)}.inline-spoiler-section.raw{background-color:#333;border-radius:2px}.inline-spoiler-section.raw>*{opacity:0}.inline-spoiler-section.unveil{cursor:auto}.inline-spoiler-section.unveil .spoiler-text{background-color:#3333331a}.inline-spoiler-section.unveil .spoiler-text>*{opacity:1}.inline-spoiler-section.unveil .spoiler-img{filter:none}@media print{blockquote,div,img,pre,table{page-break-inside:avoid!important}a[href]:after{font-size:12px!important}}.markdown-body.slides{color:#222;position:relative;z-index:1}.markdown-body.slides:before{background-color:currentColor;bottom:0;box-shadow:0 0 0 50vw;content:"";display:block;left:0;position:absolute;right:0;top:0;z-index:-1}.markdown-body.slides section[data-markdown]{background-color:#fff;margin-bottom:1.5em;position:relative;text-align:center}.markdown-body.slides section[data-markdown] code{text-align:left}.markdown-body.slides section[data-markdown]:before{content:"";display:block;padding-bottom:56.23%}.markdown-body.slides section[data-markdown]>div:first-child{left:1em;max-height:100%;overflow:hidden;position:absolute;right:1em;top:50%;transform:translateY(-50%)}.markdown-body.slides section[data-markdown]>ul{display:inline-block}.markdown-body.slides>section>section+section:after{border:3px solid #777;content:"";height:1.5em;position:absolute;right:1em;top:-1.5em}.site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,sans-serif}html[lang^=ja] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ ゴシック,sans-serif}html[lang=zh-tw] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}body{font-smoothing:subpixel-antialiased!important;-webkit-font-smoothing:subpixel-antialiased!important;-moz-osx-font-smoothing:auto!important;-webkit-overflow-scrolling:touch;font-family:Source Sans Pro,Helvetica,Arial,sans-serif;letter-spacing:.025em}html[lang^=ja] body{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ ゴシック,sans-serif}html[lang=zh-tw] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}abbr[data-original-title],abbr[title]{cursor:help}body.modal-open{overflow-y:auto;padding-right:0!important}svg{text-shadow:none}
    </style>
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js" integrity="sha256-3Jy/GbSLrg0o9y5Z5n1uw0qxZECH7C6OQpVBgNFYa0g=" crossorigin="anonymous"></script>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js" integrity="sha256-g6iAfvZp+nDQ2TdTR/VVKJf3bGro4ub5fvWSWVRi2NE=" crossorigin="anonymous"></script>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js" integrity="sha256-8E4Is26QH0bD52WoQpcB+R/tcWQtpzlCojrybUd7Mxo=" crossorigin="anonymous"></script>
    <![endif]-->
</head>

<body>
    <div id="doc" class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true"><p><strong><span>Document number</span></strong><span>: P3111R3.</span><br>
<strong><span>Date</span></strong><span>: 2025-01-13.</span><br>
<strong><span>Authors</span></strong><span>: Gonzalo Brito Gadeschi, Simon Cooksey, Daniel Lustig.</span><br>
<strong><span>Reply to</span></strong><span>: Gonzalo Brito Gadeschi &lt;gonzalob _at_ </span><a href="http://nvidia.com" target="_blank" rel="noopener"><span>nvidia.com</span></a><span>&gt;.</span><br>
<strong><span>Audience</span></strong><span>: EWG, LEWG.</span></p><style data-custom-style="">
ins {
    color:green;
    text-decoration:underline;
}
del {
    color:red;
    background-color:yellow;
    text-decoration:line-through;
}
bdi {
    color:blue;
}
.markdown-body {
    max-width: 900px;
    text-align: justify;
}
</style><p><big><span>Table of Contents</span></big></p><p><span class="toc"><ul>
<li><a href="#Atomic-Reduction-Operations" title="Atomic Reduction Operations">Atomic Reduction Operations</a><ul>
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Motivation" title="Motivation">Motivation</a><ul>
<li><a href="#Hardware-Exposure" title="Hardware Exposure">Hardware Exposure</a></li>
<li><a href="#Performance" title="Performance">Performance</a></li>
<li><a href="#Functionality" title="Functionality">Functionality</a></li>
</ul>
</li>
<li><a href="#Design" title="Design">Design</a><ul>
<li><a href="#Implementation-impact" title="Implementation impact">Implementation impact</a></li>
<li><a href="#Design-Alternatives" title="Design Alternatives">Design Alternatives</a></li>
<li><a href="#Naming" title="Naming">Naming</a></li>
<li><a href="#Memory-Ordering" title="Memory Ordering">Memory Ordering</a></li>
<li><a href="#Formalization" title="Formalization">Formalization</a></li>
</ul>
</li>
<li><a href="#Wording" title="Wording">Wording</a><ul>
<li><a href="#Forward-progress" title="Forward progress">Forward progress</a></li>
<li><a href="#No-acquire-sequences-support" title="No acquire sequences support">No acquire sequences support</a></li>
<li><a href="#Atomic-Reduction-Operation-APIs" title="Atomic Reduction Operation APIs">Atomic Reduction Operation APIs</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</span></p><p><strong><span>Changelog</span></strong></p><ul>
<li><strong><span>R3: pre Austria</span></strong><span>:</span>
<ul>
<li><span>Refactor atomic reduction sequence replacements into tables.</span></li>
<li><span>Provide alternative wording for atomic reduction sequence replacement using "as if" integer operations to provide same valid replacements as for integer reduction operations.</span></li>
</ul>
</li>
<li><strong><span>R2: post Wroclaw</span></strong><span>: simplifies reduction sequence wording.</span></li>
<li><strong><span>R1: post St. Louis '24</span></strong>
<ul>
<li><em><span>Overview of changes</span></em><span>: incorporate SG6 and SG1 feedback into the proposal, which resolved all open questions. Restructure exposition about what's being proposed accordingly.</span></li>
<li><span>[SG6 Review]:</span>
<ul>
<li><span>Forward it; does not need to look at it again.</span></li>
<li><span>Agree on "generalized" reductions being the default and not providing version without.</span></li>
<li><span>Do not use </span><code>GENERALIZED_SUM</code><span> to specify non-associative floating-point atomic reduction operations since it does not make sense for two values. Instead, attempt to add a </span><code>std::non_associative_add</code><span> operation that is exempted from the C standard clause in Annex F that makes re-ordering non-conforming. Recommended discussing this with CWG, which I did, and caused us to end up pursuing a different alternative (defining "reduction sequences") which is pursued in R1 instead.</span></li>
</ul>
</li>
<li><span>[SG1 Review]: Add wording for reduction sequences.</span></li>
<li><span>[SG1 Review]: Add </span><code>compare_store</code><span> operation.</span></li>
<li><span>[SG1 Review]: Update to handle </span><code>fenv</code><span> and </span><code>errno</code><span> for floating-point atomics.</span></li>
<li><span>[SG1 Review]: Make "generalized" atomic floating-point reductions the default and do not provide fallback (beyond </span><code>fetch_&lt;op&gt;</code><span>).</span></li>
<li><span>[SG1 Review]: Provide unsequenced support.</span></li>
<li><span>[SG1 Review]: polls taken:</span>
<ol style="padding-left: 2em;">
<li>
<p><span>Reduction operations are not a step, but infinite loops around reductions operations are not UB (practically implementations can assume reductions are finite)</span></p>
<table>
<thead>
<tr>
<th><span>SF</span></th>
<th><span>F</span></th>
<th><span>N</span></th>
<th><span>A</span></th>
<th><span>SA</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>3</span></td>
<td><span>9</span></td>
<td><span>1</span></td>
<td><span>0</span></td>
<td><span>0</span></td>
</tr>
</tbody>
</table>
</li>
<li>
<p><span>The single floating point reduction operations should allow "fast math" (allow tree reductions), you can get precise results using fetch_add/sub</span></p>
<table>
<thead>
<tr>
<th><span>SF</span></th>
<th><span>F</span></th>
<th><span>N</span></th>
<th><span>A</span></th>
<th><span>SA</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>5</span></td>
<td><span>5</span></td>
<td><span>1</span></td>
<td><span>1</span></td>
<td><span>0</span></td>
</tr>
</tbody>
</table>
</li>
<li>
<p><span>Any objection to approve the design of P3111R0: No objection.</span></p>
</li>
</ol>
</li>
</ul>
</li>
<li><strong><span>R0: initial revision</span></strong><span>.</span></li>
</ul><h1 id="Atomic-Reduction-Operations" data-id="Atomic-Reduction-Operations"><a class="anchor hidden-xs" href="#Atomic-Reduction-Operations" title="Atomic-Reduction-Operations"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Atomic Reduction Operations</span></h1><p><em><span>Atomic Reduction Operations</span></em><span> are atomic read-modify-write (RMW) operations (like </span><code>fetch_add</code><span>) that do not "fetch" the old value and are not reads for the purpose of building synchronization with acquire fences. This enables implementations to leverage hardware acceleration available in modern CPU and GPU architectures.</span></p><p><span>Furthermore, we propose to allow atomic memory operations that aren't reads in unsequenced execution, and to extend atomic arithmetic reduction operations for floating-point types with operations that assume floating-point arithmetic is associative.</span></p><h2 id="Introduction" data-id="Introduction"><a class="anchor hidden-xs" href="#Introduction" title="Introduction"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Introduction</span></h2><p><span>Concurrent algorithms performing atomic RMW operations that discard the old fetched value are very common in high-performance computing, e.g., finite-element matrix assembly, data analytics (e.g. building histograms), etc.</span></p><p><span>Consider the following parallel algorithm to build a histogram (</span><a href="https://clang.godbolt.org/z/zscrhEPYj" target="_blank" rel="noopener"><span>full implementation</span></a><span>):</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token comment">// Example 0: Histogram.</span>
span<span class="token operator">&lt;</span><span class="token keyword">unsigned</span><span class="token operator">&gt;</span> data<span class="token punctuation">;</span>

array<span class="token operator">&lt;</span>atomic<span class="token operator">&lt;</span><span class="token keyword">unsigned</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> N<span class="token operator">&gt;</span> buckets<span class="token punctuation">;</span>
<span class="token keyword">constexpr</span> T bucket_sz <span class="token operator">=</span> <span class="token class-name">numeric_limits</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token double-colon punctuation">::</span><span class="token function">max</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token punctuation">(</span>T<span class="token punctuation">)</span>N<span class="token punctuation">;</span>
<span class="token keyword">unsigned</span> nthreads <span class="token operator">=</span> thread<span class="token double-colon punctuation">::</span><span class="token function">hardware_concurrency</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">for_each_n</span><span class="token punctuation">(</span>execution<span class="token double-colon punctuation">::</span>par_unseq<span class="token punctuation">,</span> views<span class="token double-colon punctuation">::</span><span class="token function">iota</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">begin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> nthreads<span class="token punctuation">,</span> 
 <span class="token punctuation">[</span><span class="token operator">&amp;</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">int</span> thread<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">unsigned</span> data_per_thread <span class="token operator">=</span> data<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> nthreads<span class="token punctuation">;</span>
  T<span class="token operator">*</span> data_thread <span class="token operator">=</span> data<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> data_per_thread <span class="token operator">*</span> thread<span class="token punctuation">;</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">auto</span> e <span class="token operator">:</span> <span class="token generic-function"><span class="token function">span</span><span class="token generic class-name"><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>data_thread<span class="token punctuation">,</span> data_per_thread<span class="token punctuation">)</span><span class="token punctuation">)</span> 
    buckets<span class="token punctuation">[</span>e <span class="token operator">/</span> bucket_sz<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">fetch_add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</div></div></code></pre>
      </div><p><span>This program has two main issues:</span></p><ul>
<li><strong><span>Correctness</span></strong><span> (undefined behavior): The program should have used the </span><code>par</code><span> execution policy to avoid undefined behavior since the atomic operation is not:</span>
<ul>
<li><span>Potentially concurrent and therefore exhibits a data-race in unsequenced contexts ([intro.execution]).</span></li>
<li><span>Vectorization-safe </span><a href="https://eel.is/c++draft/algorithms.parallel.defns#5" target="_blank" rel="noopener"><span>[algorithms.parallel.defns#5]</span></a><span> since it is specificed to synchronize with other function invocations.</span></li>
</ul>
</li>
<li><strong><span>Performance</span></strong><span>: Sophisticated compiler analysis required to optimize the above program for scalable hardware architectures with atomic reduction operations.</span></li>
</ul><p><span>Atomic reduction operations address both shortcomings:</span></p><table>
<tbody><tr>
<td><b>Before</b> (<a href="https://clang.godbolt.org/z/xq8efq1WK" target="_blank" rel="noopener">compiler-explorer</a>)</td>
<td><b>After</b></td>
</tr>
<tr>
<td>

      <div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;algorithm&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;atomic&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;execution&gt;</span></span>
<span class="token keyword">using</span> <span class="token keyword">namespace</span> std<span class="token punctuation">;</span>
<span class="token keyword">using</span> execution<span class="token double-colon punctuation">::</span>par_unseq<span class="token punctuation">;</span>

<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  size_t N <span class="token operator">=</span> <span class="token number">10000</span><span class="token punctuation">;</span>
  vector<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;</span> <span class="token function">v</span><span class="token punctuation">(</span>N<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  atomic<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;</span> atom <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token function">for_each_n</span><span class="token punctuation">(</span>par_unseq<span class="token punctuation">,</span> 
     v<span class="token punctuation">.</span><span class="token function">begin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> N<span class="token punctuation">,</span>
    <span class="token punctuation">[</span><span class="token operator">&amp;</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">auto</span><span class="token operator">&amp;</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// UB+SLOW:</span>
      atom<span class="token punctuation">.</span><span class="token function">fetch_add</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
  <span class="token keyword">return</span> atom<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</div></div></code></pre>
      </div>
      
</td>
<td>

      <div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;algorithm&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;atomic&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;execution&gt;</span></span>
<span class="token keyword">using</span> <span class="token keyword">namespace</span> std<span class="token punctuation">;</span>
<span class="token keyword">using</span> execution<span class="token double-colon punctuation">::</span>par_unseq<span class="token punctuation">;</span>

<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  size_t N <span class="token operator">=</span> <span class="token number">10000</span><span class="token punctuation">;</span>
  vector<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;</span> <span class="token function">v</span><span class="token punctuation">(</span>N<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  atomic<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;</span> atom <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token function">for_each_n</span><span class="token punctuation">(</span>par_unseq<span class="token punctuation">,</span> 
     v<span class="token punctuation">.</span><span class="token function">begin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> N<span class="token punctuation">,</span>
    <span class="token punctuation">[</span><span class="token operator">&amp;</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">auto</span><span class="token operator">&amp;</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// OK+FAST</span>
      atom<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
  <span class="token keyword">return</span> atom<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>      
</div></div></code></pre>
      </div>
      
</td>
</tr>
</tbody></table><p><span>This new operation can then be used in the Histogram Example (example 0), to replace the </span><code>fetch_add</code><span> with </span><code>reduce_add</code><span>.</span></p><h2 id="Motivation" data-id="Motivation"><a class="anchor hidden-xs" href="#Motivation" title="Motivation"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Motivation</span></h2><h3 id="Hardware-Exposure" data-id="Hardware-Exposure"><a class="anchor hidden-xs" href="#Hardware-Exposure" title="Hardware-Exposure"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Hardware Exposure</span></h3><p><span>The following ISAs provide Atomic Reduction Operation:</span></p><table>
<thead>
<tr>
<th><span>Architecture</span></th>
<th><span>Instructions</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>PTX</span></td>
<td><a href="https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#parallel-synchronization-and-communication-instructions-red" target="_blank" rel="noopener"><code>red</code></a><span>.</span></td>
</tr>
<tr>
<td><span>ARM</span></td>
<td><a href="https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/LDADD--LDADDA--LDADDAL--LDADDL--Atomic-add-on-word-or-doubleword-in-memory-?lang=en" target="_blank" rel="noopener"><code>LDADD RZ</code></a><span>, </span><a href="https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/STADD--STADDL--Atomic-add-on-word-or-doubleword-in-memory--without-return--an-alias-of-LDADD--LDADDA--LDADDAL--LDADDL-" target="_blank" rel="noopener"><code>STADD</code></a><span>, </span><a href="https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/SWP--SWPA--SWPAL--SWPL--Swap-word-or-doubleword-in-memory-?lang=en" target="_blank" rel="noopener"><code>SWP RZ</code></a><span>, </span><a href="https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/CAS--CASA--CASAL--CASL--Compare-and-Swap-word-or-doubleword-in-memory-?lang=en" target="_blank" rel="noopener"><code>CAS RZ</code></a><span>.</span></td>
</tr>
<tr>
<td><span>x86-64</span></td>
<td><a href="https://cdrdv2-public.intel.com/671368/architecture-instruction-set-extensions-programming-reference.pdf" target="_blank" rel="noopener"><span>Remote Atomic Operations (RAO)</span></a><span>: AADD, AAND, AOR, AXOR.</span></td>
</tr>
<tr>
<td><span>RISC-V</span></td>
<td><span>None (note: AMOs are always loads and stores).</span></td>
</tr>
<tr>
<td><span>PP64LE</span></td>
<td><span>None.</span></td>
</tr>
</tbody>
</table><p><span>Some of these instructions lack a destination operand (</span><a href="https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#parallel-synchronization-and-communication-instructions-red" target="_blank" rel="noopener"><code>red</code></a><span>, </span><a href="https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/STADD--STADDL--Atomic-add-on-word-or-doubleword-in-memory--without-return--an-alias-of-LDADD--LDADDA--LDADDAL--LDADDL-" target="_blank" rel="noopener"><code>STADD</code></a><span>, AADD). Others change semantics if the destination register used discards the result (Arm's </span><a href="https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/LDADD--LDADDA--LDADDAL--LDADDL--Atomic-add-on-word-or-doubleword-in-memory-?lang=en" target="_blank" rel="noopener"><code>LDADD RZ</code></a><span>, </span><a href="https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/SWP--SWPA--SWPAL--SWPL--Swap-word-or-doubleword-in-memory-?lang=en" target="_blank" rel="noopener"><code>SWP RZ</code></a><span>, </span><a href="https://developer.arm.com/documentation/ddi0602/2022-06/Base-Instructions/CAS--CASA--CASAL--CASL--Compare-and-Swap-word-or-doubleword-in-memory-?lang=en" target="_blank" rel="noopener"><code>CAS RZ</code></a><span>).</span></p><p><span>All ISAs provide the same sematics: these are not loads from the point-of-view of the Memory Model, and therefore do not participate in acquire sequences, but they do participate in release sequences:</span></p><ul>
<li><span>PTX Specification: </span><code>red</code><span> is "</span><a href="https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#operation-types" target="_blank" rel="noopener"><span>not a read operation</span></a><span>".</span></li>
<li><span>Arm ARM: "</span><a href="https://developer.arm.com/documentation/ddi0487/latest" target="_blank" rel="noopener"><span>where the destination register is WZR or XZR, are not regarded as doing a read for the purpose of a DMB LD barrier</span></a><span>".</span></li>
<li><span>x86-64: </span><a href="https://cdrdv2-public.intel.com/671368/architecture-instruction-set-extensions-programming-reference.pdf" target="_blank" rel="noopener"><span>"since they do not load data from memory into the processor."</span></a></li>
</ul><p><span>These architectures provide both "relaxed" and "release" orderings for the reductions (e.g. </span><code>red.relaxed</code><span>/</span><code>red.release</code><span>, </span><code>STADD</code><span>/</span><code>STADDL</code><span>).</span></p><h3 id="Performance" data-id="Performance"><a class="anchor hidden-xs" href="#Performance" title="Performance"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Performance</span></h3><p><span>On hardware architectures that implement these as far atomics, the exposed latency of Atomic Reduction Operations may be as low as half that of "</span><code>fetch_&lt;key&gt;</code><span>" operations.</span></p><p><span>Example: on an NVIDIA Hopper H100 GPU, replacing </span><code>atomic.fetch_add</code><span> with </span><code>atomic.reduce_add</code><span> on the Histogram Example (Example 0) improves throughput by 1.2x.</span></p><p><span>Furthermore, non-associative floating-point atomic operations, like </span><code>fetch_add</code><span>, are required to read the "latest value", which sequentializes their execution. In the following example, the outcome </span><code>x == a + (b + c)</code><span> is not allowed, because either the atomic operation of thread0 happens-before that of thread1, or vice-versa, and floating-point arithmetic is not associative:</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token comment">// Litmus test 2:</span>
atomic<span class="token operator">&lt;</span><span class="token keyword">float</span><span class="token operator">&gt;</span> x <span class="token operator">=</span> a<span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token function">thread0</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> x<span class="token punctuation">.</span><span class="token function">fetch_add</span><span class="token punctuation">(</span>b<span class="token punctuation">,</span> memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">thread1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> x<span class="token punctuation">.</span><span class="token function">fetch_add</span><span class="token punctuation">(</span>c<span class="token punctuation">,</span> memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
</div></div></code></pre>
      </div><p><span>Allowing the </span><code>x == a + (b + c)</code><span> outcome enables implementations to perform a tree-reduction, which improves complexity from </span><code>O(N)</code><span> to </span><code>O(log(N))</code><span>, at negligible higher amount of non-determinism which is already inherent to the use of atomic operations:</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token comment">// Litmus test 3:</span>
atomic<span class="token operator">&lt;</span><span class="token keyword">float</span><span class="token operator">&gt;</span> x <span class="token operator">=</span> a<span class="token punctuation">;</span>
x<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span>b<span class="token punctuation">,</span> memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
x<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span>c<span class="token punctuation">,</span> memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Sound to merge these two operations into one:</span>
<span class="token comment">// x.reduce_add(b + c);</span>
</div></div></code></pre>
      </div><p><span>On GPU architectures, performing an horizontal reduction for then issuing a single atomic operation per thread group, reduces the number of atomic operation issued by up to the size of the thread group.</span></p><h3 id="Functionality" data-id="Functionality"><a class="anchor hidden-xs" href="#Functionality" title="Functionality"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Functionality</span></h3><p><span>Currently, all atomic memory operations are </span><a href="https://eel.is/c++draft/algorithms.parallel.defns#5" target="_blank" rel="noopener"><span>vectorization-unsafe</span></a><span> and therefore not allowed in element access functions of parallel algorithms when the </span><code>unseq</code><span> or </span><code>par_unseq</code><span> execution policies are used (see </span><a href="https://eel.is/c++draft/algorithms.parallel#exec-5" target="_blank" rel="noopener"><span>[algorithms.parallel.exec.5]</span></a><span> and </span><a href="https://eel.is/c++draft/algorithms.parallel#exec-7" target="_blank" rel="noopener"><span>[algorithms.parallel.exec.7]</span></a><span>). Atomic memory operations that "read" (e.g. </span><code>load</code><span>, </span><code>fetch_&lt;key&gt;</code><span>, </span><code>compare_exchange</code><span>, </span><code>exchange</code><span>, </span><span class="smartypants">…</span><span>) enable building synchronization edges that block, which within </span><code>unseq</code><span>/</span><code>par_unseq</code><span> leads to dead-locks. </span><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4070.html" target="_blank" rel="noopener"><span>N4070</span></a><span> solved this by tightening the wording to disallow any synchronization API from being called from within </span><code>unseq</code><span>/</span><code>par_unseq</code><span>.</span></p><p><span>Allowing Atomic Writes and Atomic Reduction Operations in unsequenced execution increases the set of concurrent algorithms that can be implemented in the lowest-common denominator of hardware that C++ supports. In particular, many hardware architectures that can accelerate </span><code>unseq</code><span>/</span><code>par_unseq</code><span> but cannot accelerate </span><code>par</code><span> (e.g. most non-NVIDIA GPUs), provide acceleration for atomic reduction operations.</span></p><p><span>We propose to make lock-free atomic operations that are not reads vectorization safe to enable calling them from unsequenced execution. Atomic operations that read remain vectorization-unsafe and therefore UB:</span></p><h2 id="Design" data-id="Design"><a class="anchor hidden-xs" href="#Design" title="Design"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Design</span></h2><p><span>For each atomic </span><code>fetch_{OP}</code><span> in the </span><code>atomic&lt;T&gt;</code><span> and </span><code>atomic_ref&lt;T&gt;</code><span> class templates and their specializations, we introduce new </span><code>reduce_{OP}</code><span> member functions that return </span><code>void</code><span>:</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token keyword">template</span> <span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">T</span><span class="token operator">&gt;</span>
<span class="token keyword">struct</span> <span class="token class-name">atomic_ref</span> <span class="token punctuation">{</span>
  T    <span class="token function">fetch_add</span> <span class="token punctuation">(</span>T v<span class="token punctuation">,</span> memory_order o<span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token keyword">noexcept</span><span class="token punctuation">;</span>
  <span class="token keyword">void</span> <span class="token function">reduce_add</span><span class="token punctuation">(</span>T v<span class="token punctuation">,</span> memory_order o<span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token keyword">noexcept</span><span class="token punctuation">;</span> 
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</div></div></code></pre>
      </div><p><span>We also introduce </span><code>compare_store</code><span>, which is the Atomic Reduction Operation analogous of </span><code>compare_exchange</code><span>:</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token keyword">template</span> <span class="token operator">&lt;</span><span class="token keyword">class</span> <span class="token class-name">T</span><span class="token operator">&gt;</span>
<span class="token keyword">struct</span> <span class="token class-name">atomic_ref</span> <span class="token punctuation">{</span>
  <span class="token keyword">bool</span> <span class="token function">compare_exchange_weak</span><span class="token punctuation">(</span>T<span class="token operator">&amp;</span> expected<span class="token punctuation">,</span> T desired<span class="token punctuation">,</span> memory_order o<span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token keyword">noexcept</span><span class="token punctuation">;</span>
  <span class="token keyword">void</span> <span class="token function">compare_store</span>        <span class="token punctuation">(</span>T  expected<span class="token punctuation">,</span> T desired<span class="token punctuation">,</span> memory_order o<span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token keyword">noexcept</span><span class="token punctuation">;</span> 
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</div></div></code></pre>
      </div><p><span>The </span><code>reduce_{OP}</code><span> and </span><code>compare_store</code><span> APIs are vectorization safe if the atomic </span><code>is_always_lock_free</code><span> is true, i.e., they are allowed in Element Access Functions (</span><a href="https://eel.is/c++draft/algorithms.parallel.defns#def:element_access_functions" target="_blank" rel="noopener"><span>[algorithms.paralle.defns]</span></a><span>) of parallel algorithms:</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><span class="token function">for_each</span><span class="token punctuation">(</span>par_unseq<span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token operator">&amp;</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">auto</span> old<span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">assert</span><span class="token punctuation">(</span>atom<span class="token punctuation">.</span><span class="token function">is_lockfree</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Only for lock-free atomics</span>
    atom<span class="token punctuation">.</span><span class="token function">store</span><span class="token punctuation">(</span><span class="token number">42</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token comment">// OK: vectorization-safe</span>
    atom<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// OK: vectorization-safe</span>
    atom<span class="token punctuation">.</span><span class="token function">compare_store</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// OK: vectorization-safe</span>
    atom<span class="token punctuation">.</span><span class="token function">fetch_add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>         <span class="token comment">// UB: vectorization-unsafe</span>
    atom<span class="token punctuation">.</span><span class="token function">exchange</span><span class="token punctuation">(</span><span class="token number">42</span><span class="token punctuation">)</span><span class="token punctuation">;</span>         <span class="token comment">// UB: vectorization-unsafe</span>
    atom<span class="token punctuation">.</span><span class="token function">compare_exchange_weak</span><span class="token punctuation">(</span>old<span class="token punctuation">,</span> <span class="token number">42</span><span class="token punctuation">)</span><span class="token punctuation">;</span>   <span class="token comment">// UB: vectorization-unsafe</span>
    atom<span class="token punctuation">.</span><span class="token function">compare_exchange_strong</span><span class="token punctuation">(</span>old<span class="token punctuation">,</span> <span class="token number">42</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// UB: vectorization-unsafe</span>
    <span class="token keyword">while</span> <span class="token punctuation">(</span>atom<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;</span> <span class="token number">42</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// UB: vectorization-unsafe</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
</code></pre>
      </div><p><span>Furthermore, we specify non-associative floating-point atomic reduction operations to enable tree-reduction implementations that improve complexity from </span><code>O(N)</code><span> to </span><code>O(log(N))</code><span> by minimally increasing the non-determinism which is already inherent to atomic operations. This allows producing the </span><code>x == a + (b + c)</code><span> outcome in the following example, which enables the optimization that merges the two </span><code>reduce_add</code><span> operations into a single one:</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code">atomic<span class="token operator">&lt;</span><span class="token keyword">float</span><span class="token operator">&gt;</span> x <span class="token operator">=</span> a<span class="token punctuation">;</span>
x<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span>b<span class="token punctuation">,</span> memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
x<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span>c<span class="token punctuation">,</span> memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Sound to merge these two operations into one:</span>
<span class="token comment">// x.store_add(b + c);</span>
</div></div></code></pre>
      </div><p><span>Applications that need the sequential semantics can use </span><code>fetch_add</code><span> instead.</span></p><h3 id="Implementation-impact" data-id="Implementation-impact"><a class="anchor hidden-xs" href="#Implementation-impact" title="Implementation-impact"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Implementation impact</span></h3><p><span>It is correct to conservatively implement </span><code>reduce_{OP}</code><span> as a call to </span><code>fetch_{OP}</code><span>. We evaluated the following implementations of unsequenced execution policies, which are not impacted:</span></p><ul>
<li><span>OpenMP </span><a href="https://www.openmp.org/spec-html/5.0/openmpsu42.html" target="_blank" rel="noopener"><span>simd</span></a><span> pragma for </span><code>unseq</code><span> and </span><code>par_unseq</code><span>, since OpenMP supports atomics within </span><code>simd</code><span> regions.</span></li>
<li><a href="https://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations" target="_blank" rel="noopener"><span>pragma clang loop</span></a><span> is a hint.</span></li>
</ul><h3 id="Design-Alternatives" data-id="Design-Alternatives"><a class="anchor hidden-xs" href="#Design-Alternatives" title="Design-Alternatives"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Design Alternatives</span></h3><h4 id="Enable-Atomic-Reductions-as-fetch_ltkeygt-optimizations" data-id="Enable-Atomic-Reductions-as-fetch_ltkeygt-optimizations"><a class="anchor hidden-xs" href="#Enable-Atomic-Reductions-as-fetch_ltkeygt-optimizations" title="Enable-Atomic-Reductions-as-fetch_ltkeygt-optimizations"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Enable Atomic Reductions as </span><code>fetch_&lt;key&gt;</code><span> optimizations</span></h4><p><span>Attempting to improve application performance by implementing compiler-optimizations to leverage Atomic Reduction Operations from </span><code>fetch_&lt;key&gt;</code><span> APIs whose result is unused has become a rite of passage for compiler engineers, e.g., </span><a href="https://gcc.gnu.org/pipermail/gcc-patches/2018-October/509632.html" target="_blank" rel="noopener"><span>GCC#509632</span></a><span>, </span><a href="https://github.com/llvm/llvm-project/issues/68428" target="_blank" rel="noopener"><span>LLVM#68428</span></a><span>, </span><a href="https://github.com/llvm/llvm-project/pull/72747" target="_blank" rel="noopener"><span>LLVM#72747</span></a><span>, </span><span class="smartypants">…</span><span> Unfortunately, "simple" optimization strategies break backward compatibility in the following litmus tests (among others).</span></p><p><strong><span>Litmus Test 0</span></strong><span>: from </span><a href="https://gcc.gnu.org/pipermail/gcc-patches/2018-October/509632.html" target="_blank" rel="noopener"><span>Will Deacon</span></a><span>. Performing the optimization to replace the  introduces the </span><code>y == 2 &amp;&amp; r0 == 1 &amp;&amp; r1 == 0</code><span> outcome:</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token keyword">void</span> <span class="token function">thread0</span><span class="token punctuation">(</span>atomic_int<span class="token operator">*</span> y<span class="token punctuation">,</span>atomic_int<span class="token operator">*</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">atomic_store_explicit</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span>memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">atomic_thread_fence</span><span class="token punctuation">(</span>memory_order_release<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">atomic_store_explicit</span><span class="token punctuation">(</span>y<span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span>memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">void</span> <span class="token function">thread1</span><span class="token punctuation">(</span>atomic_int<span class="token operator">*</span> y<span class="token punctuation">,</span>atomic_int<span class="token operator">*</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">atomic_fetch_add_explicit</span><span class="token punctuation">(</span>y<span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span>memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">atomic_thread_fence</span><span class="token punctuation">(</span>memory_order_acquire<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">int</span> r0 <span class="token operator">=</span> <span class="token function">atomic_load_explicit</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span>memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">void</span> <span class="token function">thread2</span><span class="token punctuation">(</span>atomic_int<span class="token operator">*</span> y<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">int</span> r1 <span class="token operator">=</span> <span class="token function">atomic_load_explicit</span><span class="token punctuation">(</span>y<span class="token punctuation">,</span>memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</div></div></code></pre>
      </div><p><strong><span>Litmus Test 1</span></strong><span>: from </span><a href="https://github.com/llvm/llvm-project/issues/68428#issue-1930595855" target="_blank" rel="noopener"><span>Luke Geeson</span></a><span>. Performing the optimization of replacing the exchange with a store introduces the </span><code>r0 == 0 &amp;&amp; y == 2</code><span> outcome:</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token keyword">void</span> <span class="token function">thread0</span><span class="token punctuation">(</span>atomic_int<span class="token operator">*</span> y<span class="token punctuation">,</span>atomic_int<span class="token operator">*</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">atomic_store_explicit</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span>memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">atomic_thread_fence</span><span class="token punctuation">(</span>memory_order_release<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">atomic_store_explicit</span><span class="token punctuation">(</span>y<span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span>memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">thread1</span><span class="token punctuation">(</span>atomic_int<span class="token operator">*</span> y<span class="token punctuation">,</span>atomic_int<span class="token operator">*</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">atomic_exchange_explicit</span><span class="token punctuation">(</span>y<span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span>memory_order_release<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">atomic_thread_fence</span><span class="token punctuation">(</span>memory_order_acquire<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">int</span> r0 <span class="token operator">=</span> <span class="token function">atomic_load_explicit</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span>memory_order_relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</div></div></code></pre>
      </div><p><span>In some architectures, Atomic Reduction Operations can write to memory pages or memory locations that are not readable, e.g., MMIO registers on NVIDIA GPUs, and need a reliable programming model that does not depend on compiler-optimizations for functionality.</span></p><h3 id="Naming" data-id="Naming"><a class="anchor hidden-xs" href="#Naming" title="Naming"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Naming</span></h3><p><span>We considered the following alternative names:</span></p><ul>
<li><code>atomic.add</code><span>: breaks for logical operations (e.g. </span><code>atomic.and</code><span>, etc.).</span></li>
<li><code>atomic.store_add</code><span>: clearly states that this operation is a "store" (and not a "load").</span></li>
<li><code>atomic.reduce_add</code><span>: clearly state what this operation is for (reductions).</span></li>
</ul><p><span>We considered providing separate version of non-associative floating-point atomic reduction operations with and without the support for tree-reductions, e.g., </span><code>atomic.reduce_add</code><span> (no tree-reduction support) and </span><code>atomic.reduce_add_generalized</code><span> (tree-reduction support), but decided against it because atomic operations are inherently non-deterministic, this relaxation only minimally impacts that, and </span><code>fetch_add</code><span> already provides (and has to continue to provide) the sequential semantics without this relaxation.</span></p><h3 id="Memory-Ordering" data-id="Memory-Ordering"><a class="anchor hidden-xs" href="#Memory-Ordering" title="Memory-Ordering"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Memory Ordering</span></h3><p><span>We choose to support </span><code>memory_order_relaxed</code><span>, </span><code>memory_order_release</code><span>, and </span><code>memory_order_seq_cst</code><span>.</span></p><p><span>We may need a note stating that replacing the operations in a reduction sequence is only valid as long as the replacement maintains the other ordering properties of the operations as defined in [intro.races]. Examples:</span></p><p><strong><span>Litmus test 2:</span></strong></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token comment">// T0:</span>
M1<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
M2<span class="token punctuation">.</span><span class="token function">store</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> release<span class="token punctuation">)</span><span class="token punctuation">;</span>
M1<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>
    
<span class="token comment">// T1:</span>
r0 <span class="token operator">=</span> M2<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>acquire<span class="token punctuation">)</span><span class="token punctuation">;</span>
r1 <span class="token operator">=</span> M1<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>relaxed<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// r0 == 0 || r1 &gt;= 1</span>
</div></div></code></pre>
      </div><p><strong><span>Litmus test 3:</span></strong></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token comment">// T0</span>
M1<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> seq_cst<span class="token punctuation">)</span><span class="token punctuation">;</span>
M2<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> seq_cst<span class="token punctuation">)</span><span class="token punctuation">;</span>
M1<span class="token punctuation">.</span><span class="token function">reduce_add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> seq_cst<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// T1</span>
r0 <span class="token operator">=</span> M2<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>seq_cst<span class="token punctuation">)</span><span class="token punctuation">;</span>
r1 <span class="token operator">=</span> M1<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>seq_cst<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// r0 == 0 || r1 &gt;= 1</span>
</div></div></code></pre>
      </div><p><bdi><strong><span>Unresolved question</span></strong><span>: Are tree reductions only supported for </span><code>memory_order_relaxed</code><span>? No, see litmus tests for release and seq_cst.</span></bdi></p><h3 id="Formalization" data-id="Formalization"><a class="anchor hidden-xs" href="#Formalization" title="Formalization"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Formalization</span></h3><p><span>Herd already support these for </span><code>STADD</code><span> on Arm, and the NVIDIA Volta Memory Model supports these for </span><code>red</code><span> and </span><code>multimem.red</code><span> on PTX. If we decide to pursue this exposure direction, this proposal would benefit from extending Herd's</span><span class="ui-comment-inline-span"> RC11 with </span><span>reduction sequences for floating-point.</span></p><h2 id="Wording" data-id="Wording"><a class="anchor hidden-xs" href="#Wording" title="Wording"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Wording</span></h2><details><summary>Do NOT modify [intro.execution.10]!</summary>
<p><span>We do not need to modify </span><a href="https://eel.is/c++draft/basic.exec#intro.execution-10" target="_blank" rel="noopener"><span>[intro.execution.10]</span></a><span> to enable using atomic reduction operations in unsequenced contexts, because this section does not prevent that: </span><code>atomic.foo()</code><span> are function calls and two function calls are always indeterminately sequenced, not unsequenced. That is, function calls never overlap, and this section does not impact that.</span></p>
<blockquote>
<p><span>Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.</span><br>
<span>[Note 5: In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations. — end note]</span></p>
<p><span>The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a memory location ([intro.memory]) is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, and they are not </span><ins><span>lock-free atomic read operations ([atomics]) or </span></ins><span>potentially concurrent ([intro.multithread]), the behavior is undefined.</span><br>
<span>[Note 6: The next subclause imposes similar, but more complex restrictions on potentially concurrent computations. — end note]</span></p>
</blockquote>
<blockquote>
<p><span>[Example 3:</span></p>

      <div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><span class="token keyword">void</span> <span class="token function">g</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
 i <span class="token operator">=</span> <span class="token number">7</span><span class="token punctuation">,</span> i<span class="token operator">++</span><span class="token punctuation">,</span> i<span class="token operator">++</span><span class="token punctuation">;</span>              <span class="token comment">// i becomes 9</span>

 i <span class="token operator">=</span> i<span class="token operator">++</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>                  <span class="token comment">// the value of i is incremented</span>
 i <span class="token operator">=</span> i<span class="token operator">++</span> <span class="token operator">+</span> i<span class="token punctuation">;</span>                  <span class="token comment">// undefined behavior</span>
 i <span class="token operator">=</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>                    <span class="token comment">// the value of i is incremented</span>
<span class="token punctuation">}</span>
</code></pre>
      </div>
      
<p><span>— end example]</span></p>
</blockquote>
</details><p><span>Add to </span><a href="https://eel.is/c++draft/intro.races" target="_blank" rel="noopener"><span>[intro.races]</span></a><span> before </span><a href="https://eel.is/c++draft/intro.races#14" target="_blank" rel="noopener"><span>[intro.races.14]</span></a><span>:</span></p><p><bdi><strong><span>Review Note</span></strong><span>: the intent of this wording change is to enable tree-reduction implementations for non-associative floating-point atomic reduction operations which, in this proposal, are only </span><code>reduce_add</code><span> and </span><code>reduce_sub</code><span>. SG1 agreed that the single floating point reduction operations should allow "fast math" (allow tree reductions) because programs can get precise results using </span><code>fetch_add</code><span>/</span><code>sub</code><span>. Alternative wording strategies using </span><code>GENERALIZED_NONCOMMUTATIVE_SUM</code><span> were explored but are not viable since only two values are involved.</span></bdi><br>
<bdi><strong><span>Review Note</span></strong><span>: Since other proposals in flight add </span><code>fetch_mul</code><span> and </span><code>fetch_div</code><span>, and those would need to extend this, this revision of this paper shows how that would look like by introducing "multiplicative reduction sequences".</span></bdi><br>
<bdi><strong><span>Review Note</span></strong><span>: For integers, implementations are already allowed to perform tree reductions, as long as they don't violate any other ordering rules. The only goal of the following reduction sequence wording is to allow the exact same thing for floats, since implementation cannot perform tree reductions because the ops are not associative and impact the results. Maybe instead of adding all of this wording, we could instead say that reduction operations on floats may be re-ordered or re-associated "as if" they were operations on integers? For example, we could add a Remark to the floating-point specialization of atomic and atomic_ref that just says: "Remark: The associativity of floating-point atomic reduction operations is the same as that of integers."</span></bdi></p><p><bdi><strong><span>Option A.0</span></strong><span>: this option specifies the optimization that is allowed for floating-point atomic reduction operations.</span></bdi><span>.</span></p><ol style="padding-left: 2em;">
<li><ins><span> A </span><em><span>reduction sequence</span></em><span> is a maximal contiguous sub-sequence of side effects in the modification order of M, where each operation is an atomic reduction operation. If replacing two adjacent integer operations in a reduction sequence is not observable, this same replacement may be performed for two adjacent floating-point operations in a reduction sequence.</span></ins><br>
<ins><span>[Note 1: Combining adjacent operations in a reduction sequence is often not observable for integer operations but is often observable for floating-point operations due to associativity. This paragraph enables implementations to optimize floating-point atomic reduction operations using tree reductions. - end note]</span></ins></li>
</ol><p><bdi><span>Alternative A.1: Replace the last sentence in the paragraph with: "Any two adjacent floating-point operations in a reduction sequence can be replaced by a single operation as if the operations were integer operations.".</span></bdi></p><p><bdi><strong><span>Option B</span></strong><span>: this option explicitly specify the allowed replacements for floating-point operations using a table.</span></bdi></p><ol style="padding-left: 2em;">
<li><ins><span>A </span><em><span>reduction sequence</span></em><span> is a maximal contiguous sub-sequence of side effects in the modification order of M, where each operation is an atomic reduction operation. Any two adjacent floating-point operations in a reduction sequence whose replacement does not contradict any memory ordering requirements can be replaced by a single operation, recursively, as specified in Table [tab.red.seq.replacement]. The replaced operation uses the largest memory order of both operations according to </span><code>memory_order_relaxed &lt; memory_order_release &lt; memory_order_seq_cst</code><span>. For signed integer types, the intermediate computation is performed as if the objects </span><code>a</code><span> and </span><code>b</code><span> were converted to their corresponding unsigned types, and its result converted back to the signed type.</span></ins><br>
<ins><span>[Note 1: Replacing any two adjacent operations in a reduction sequence is only valid if the replacement maintains the other ordering properties of the operations as defined in [intro.races]. The assertion in the following example holds:</span></ins></li>
</ol><pre><code><ins>atomic&lt;int&gt; M0 = 0, M1 = 0;</ins>
<ins>void thread0() {</ins>
  <ins>M0.reduce_add(1, memory_order_relaxed);</ins>
  <ins>M1.store(1, memory_order_release);</ins>
  <ins>M0.reduce_add(1, memory_order_relaxed);</ins>
<ins>}</ins>
<ins>void thread1() {</ins>
  <ins>auto r0 = M1.load(memory_order_acquire);</ins>
  <ins>auto r1 = M0.load(memory_order_relaxed);</ins>
  <ins>assert(r0 == 0 || r1 &gt;= 1);</ins>
<ins>}</ins></code></pre><p><ins><span> That is, replacing the two adjacent </span><code>M0.reduce_add</code><span> on </span><code>thread0</code><span> with a single </span><code>reduce_add</code><span> after the </span><code>M1</code><span> release store as follows:</span></ins></p><pre><code><ins>void thread0() {</ins>
  <ins>M1.store(1, memory_order_release);</ins>
  <ins>M0.reduce_add(2, memory_order_relaxed);</ins>
<ins>}</ins></code></pre><p><ins><span> is not allowed, but replacing them before the store as follows:</span></ins></p><ul>
<li><span>end note]</span></li>
</ul><p><ins><span>Table [tab.red.seq.replacement]: Allowed replacements of two adjacent floating-point atomic reduction operations </span><code>reduce_&lt;key&gt;</code><span> within a floating-point atomic reduction sequence on memory location M, where the value parameter of the first atomic operation is </span><code>a</code><span>, and that of the second is </span><code>b</code><span>.</span></ins></p><table>
<thead>
<tr>
<th><span>Second Op </span><br><span> First Op</span></th>
<th><code>add</code></th>
<th><code>sub</code></th>
<th><code>min</code></th>
<th><code>max</code></th>
</tr>
</thead>
<tbody>
<tr>
<td><code>add</code></td>
<td><code>add(a + b)</code></td>
<td><code>add(a - b)</code></td>
<td><span>n/a</span></td>
<td><span>n/a</span></td>
</tr>
<tr>
<td><code>sub</code></td>
<td><code>add(b - a)</code></td>
<td><code>sub(a + b)</code></td>
<td><span>n/a</span></td>
<td><span>n/a</span></td>
</tr>
<tr>
<td><code>min</code></td>
<td><span>n/a</span></td>
<td><span>n/a</span></td>
<td><code>min(min(a,b))</code></td>
<td><span>n/a</span></td>
</tr>
<tr>
<td><code>max</code></td>
<td><span>n/a</span></td>
<td><span>n/a</span></td>
<td><span>n/a</span></td>
<td><code>max(max(a,b))</code></td>
</tr>
</tbody>
</table><p><bdi><strong><span>Option B.1</span></strong><span>:  this option may be extended to mul and div operations as follows:</span></bdi></p><table>
<thead>
<tr>
<th><span>Second Op </span><br><span> First Op</span></th>
<th><code>mul</code></th>
<th><code>div</code></th>
</tr>
</thead>
<tbody>
<tr>
<td><code>mul</code></td>
<td><code>mul(a * b)</code></td>
<td><code>mul(a / b)</code></td>
</tr>
<tr>
<td><code>div</code></td>
<td><code>mul(b / a)</code></td>
<td><code>div(a * b)</code></td>
</tr>
</tbody>
</table><p><bdi><strong><span>Option B.2</span></strong><span>:  this option explicitly specify the allowed replacements for floating-point operations without a table.</span></bdi></p><ol style="padding-left: 2em;">
<li><ins><span class="smartypants">…</span><span> as specified below, recursively:</span></ins>
<ul>
<li><ins><code>M.reduce_add(a, o0)</code><span> and </span><code>M.reduce_add(b, o1)</code><span> can be replaced with </span><code>M.reduce_add(a + b, max_order(o0, o1))</code><span>,</span></ins></li>
<li><ins><code>M.reduce_sub(a, o0)</code><span> and </span><code>M.reduce_sub(b, o1)</code><span> can be replaced with </span><code>M.reduce_sub(a + b, max_order(o0, o1))</code><span>,</span></ins></li>
<li><ins><code>M.reduce_add(a, o0)</code><span> and </span><code>M.reduce_sub(b, o1)</code><span> can be replaced with </span><code>M.reduce_add(a - b, max_order(o0, o1))</code><span>,</span></ins></li>
<li><ins><code>M.reduce_sub(a, o0)</code><span> and </span><code>M.reduce_add(b, o1)</code><span> can be replaced with </span><code>M.reduce_add(b - a, max_order(o0, o1))</code><span>,</span></ins></li>
<li><ins><code>M.reduce_mul(a, o0)</code><span> and </span><code>M.reduce_mul(b, o1)</code><span> can be replaced with </span><code>M.reduce_mul(a * b, max_order(o0, o1))</code><span>,</span></ins></li>
<li><ins><code>M.reduce_div(a, o0)</code><span> and </span><code>M.reduce_div(b, o1)</code><span> can be replaced with </span><code>M.reduce_div(a * b, max_order(o0, o1))</code><span>,</span></ins></li>
<li><ins><code>M.reduce_mul(a, o0)</code><span> and </span><code>M.reduce_div(b, o1)</code><span> can be replaced with </span><code>M.reduce_mul(a / b, max_order(o0, o1))</code><span>,</span></ins></li>
<li><ins><code>M.reduce_div(a, o0)</code><span> and </span><code>M.reduce_mul(b, o1)</code><span> can be replaced with </span><code>M.reduce_mul(b / a, max_order(o0, o1))</code><span>,</span></ins></li>
<li><ins><code>M.reduce_min(a, o0)</code><span> and </span><code>M.reduce_min(b, o1)</code><span> can be replaced with </span><code>M.reduce_min(min(a, b), max_order(o0, o1))</code><span>,</span></ins></li>
<li><ins><code>M.reduce_max(a, o0)</code><span> and </span><code>M.reduce_max(b, o1)</code><span> can be replaced with </span><code>M.reduce_max(max(a, b), max_order(o0, o1))</code><span>.</span></ins></li>
</ul>
</li>
</ol><p><span>Add to </span><a href="https://eel.is/c++draft/algorithms.parallel.defns#5" target="_blank" rel="noopener"><span>[algorithms.parallel.defns]</span></a><span>:</span></p><p><bdi><strong><span>Review note</span></strong><span>: the first bullet says which standard library functions are, in general, vectorization unsafe, and the second bullet carves out exceptions.</span></bdi><br>
<bdi><strong><span>Review note</span></strong><span>: the current wording intent is for </span><code>fetch_add(relaxed)</code><span> to be vectorization-unsafe, but the standard words in [intro.execution.10] (see above) that were supposed to fix that, do not. So we currently ban those here as a drive-by change that should be filled as LWG defect report, but that this proposal would then need to carve out an exception for atomic reduction operations.</span></bdi><br>
<bdi><strong><span>Review Note</span></strong><span>: SG1 requested making "relaxed", "release", and "seq_cst" atomic reduction operations not be vectorization unsafe, and that is the intent of the words below.</span></bdi></p><blockquote>
<p><span>A standard library function is vectorization-unsafe if:</span></p>
<ul>
<li><span>it is specified to synchronize with another function invocation, or another function invocation is specified to synchronize with it,</span><del><span>and</span></del><ins><span>or it is a relaxed atomic operation </span><a href="https://eel.is/c++draft/atomics.order" target="_blank" rel="noopener"><span>[atomics.order]</span></a><span>, and</span></ins></li>
<li><del><span>if </span></del><span>it is not a memory allocation or deallocation function</span><ins><span class="ui-comment-inline-span"> or lock-free atomic reduction operation</span></ins><span>.</span></li>
</ul>
<p><span>[Note 2: Implementations must ensure that internal synchronization inside standard library functions does not prevent forward progress when those functions are executed by threads of execution with weakly parallel forward progress guarantees. — end note]</span></p>
<p><span>[Example 2:</span></p>

      <div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><span class="token keyword">int</span> x <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
std<span class="token double-colon punctuation">::</span>mutex m<span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">int</span> a<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  std<span class="token double-colon punctuation">::</span><span class="token function">for_each</span><span class="token punctuation">(</span>std<span class="token double-colon punctuation">::</span>execution<span class="token double-colon punctuation">::</span>par_unseq<span class="token punctuation">,</span> std<span class="token double-colon punctuation">::</span><span class="token function">begin</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">,</span> std<span class="token double-colon punctuation">::</span><span class="token function">end</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token operator">&amp;</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    std<span class="token double-colon punctuation">::</span>lock_guard<span class="token operator">&lt;</span>mutex<span class="token operator">&gt;</span> <span class="token function">guard</span><span class="token punctuation">(</span>m<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// incorrect: lock_guard constructor calls m.lock()</span>
    <span class="token operator">++</span>x<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
      </div>
      
<p><span>The above program may result in two consecutive calls to m.lock() on the same thread of execution (which may deadlock), because the applications of the function object are not guaranteed to run on different threads of execution. — end example]</span></p>
</blockquote><h3 id="Forward-progress" data-id="Forward-progress"><a class="anchor hidden-xs" href="#Forward-progress" title="Forward-progress"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Forward progress</span></h3><p><span>Modify </span><a href="https://eel.is/c++draft/intro.progress#1" target="_blank" rel="noopener"><span>[intro.progress#1]</span></a><span> as follows:</span></p><p><bdi><strong><span>Review Note</span></strong><span>: SG1 design intent is that Reduction operations are not a step, but infinite loops around reductions operations are not UB (practically implementations can assume reductions are finite). Gonzalo's note: such loops cause all threads to loose forward progress.</span></bdi><br>
<bdi><strong><span>Review Note</span></strong><span>: this change makes Atomic Reduction Operations and Atomic Stores/Fences asymmetric, but making this change for Atomic Stores/Fences is a breaking change to be pursued in a separate paper per SG1 feedback. When adding these new operations, it does make sense to make this change, to avoid introducing undesired semantics that would be a breaking change to fix.</span></bdi></p><blockquote>
<p><span>The implementation may assume that any thread will eventually do one of the following:</span></p>
<ol style="padding-left: 2em;">
<li><span>terminate,</span></li>
<li><span>invoke the function std​::​this_thread​::​yield ([thread.thread.this]),</span></li>
<li><span>make a call to a library I/O function,</span></li>
<li><span>perform an access through a volatile glvalue, or</span></li>
<li><span>perform a synchronization operation or an atomic operation</span><ins><span> other than an atomic reduction operation </span><a href="https://eel.is/c++draft/atomics.order" target="_blank" rel="noopener"><span>[atomics.order]</span></a></ins><span>, or</span></li>
<li><span>continue execution of a trivial infinite loop ([stmt.iter.general]).</span></li>
</ol>
<p><span>[Note 1: This is intended to allow compiler transformations such as removal of empty loops, even when termination cannot be proven. — end note]</span></p>
</blockquote><p><span>Modify </span><a href="https://eel.is/c++draft/intro.progress#3" target="_blank" rel="noopener"><span>[intro.progress#3]</span></a><span> as follows:</span></p><p><bdi><strong><span>Review note</span></strong><span>: same note as above about exempting atomic stores in a separate paper.</span></bdi></p><blockquote>
<p><span>During the execution of a thread of execution, each of the following is termed an execution step:</span></p>
<ol style="padding-left: 2em;">
<li><span>termination of the thread of execution,</span></li>
<li><span>performing an access through a volatile glvalue, or</span></li>
<li><span>completion of a call to a library I/O function, </span><ins><span>or</span></ins><span> a synchronization operation</span><del><span>,</span></del><span> or an atomic operation</span><ins><span> other than an atomic reduction operation </span><a href="https://eel.is/c++draft/atomics.order" target="_blank" rel="noopener"><span>[atomics.order]</span></a></ins><span>.</span></li>
</ol>
</blockquote><h3 id="No-acquire-sequences-support" data-id="No-acquire-sequences-support"><a class="anchor hidden-xs" href="#No-acquire-sequences-support" title="No-acquire-sequences-support"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>No acquire sequences support</span></h3><p><span>Modify </span><a href="https://eel.is/c++draft/atomics.fences" target="_blank" rel="noopener"><span>[atomics.fences]</span></a><span> as follows:</span></p><blockquote>
<p><span>33.5.11 Fences[atomics.fences]</span></p>
<ol style="padding-left: 2em;">
<li><span>This subclause introduces synchronization primitives called fences. Fences can have acquire semantics, release semantics, or both. A fence with acquire semantics is called an acquire fence. A fence with release semantics is called a release fence.</span></li>
<li><span>A release fence A synchronizes with an acquire fence B if there exist atomic operations X and Y, </span><ins><span>where Y is not an atomic reduction operation </span><a href="https://eel.is/c++draft/atomics.order" target="_blank" rel="noopener"><span>[atomics.order]</span></a><span>, </span></ins><span>both operating on some atomic object M, such that A is sequenced before X, X modifies M, Y is sequenced before B, </span><span class="ui-comment-inline-span">and Y reads the value written </span><span>by X or a value written by any side effect in the hypothetical release sequence X would head if it were a release operation.</span></li>
<li><span>A release fence A synchronizes with an atomic operation B that performs an acquire operation on an atomic object M if there exists an atomic operation X such that A is sequenced before X, X modifies M, and B reads the value written by X or a value written by any side effect in the hypothetical release sequence X would head if it were a release operation.</span></li>
<li><span>An atomic operation A that is a release operation on an atomic object M synchronizes with an acquire fence B if there exists some atomic operation X on M such that X is sequenced before B and reads the value written by A or a value written by any side effect in the release sequence headed by A.</span></li>
</ol>
</blockquote><h3 id="Atomic-Reduction-Operation-APIs" data-id="Atomic-Reduction-Operation-APIs"><a class="anchor hidden-xs" href="#Atomic-Reduction-Operation-APIs" title="Atomic-Reduction-Operation-APIs"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Atomic Reduction Operation APIs</span></h3><p><span>The following operations perform arithmetic computations. The correspondence among key, operator, and computation is specified in </span><a href="https://eel.is/c++draft/atomics#tab:atomic.types.int.comp" target="_blank" rel="noopener"><span>Table 145</span></a><span>:</span></p><table>
<thead>
<tr>
<th><span>key</span></th>
<th><span>op</span></th>
<th><span>computation</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>add</span></td>
<td><code>+</code></td>
<td><span>addition</span></td>
</tr>
<tr>
<td><span>sub</span></td>
<td><code>-</code></td>
<td><span>subtraction</span></td>
</tr>
<tr>
<td><span>max</span></td>
<td></td>
<td><span>maximum</span></td>
</tr>
<tr>
<td><span>min</span></td>
<td></td>
<td><span>minimum</span></td>
</tr>
<tr>
<td><span>and</span></td>
<td><code>&amp;</code></td>
<td><span>bitwise and</span></td>
</tr>
<tr>
<td><span>or</span></td>
<td><code>|</code></td>
<td><span>bitwise inclusive or</span></td>
</tr>
<tr>
<td><span>xor</span></td>
<td><code>^</code></td>
<td><span>bitwise exclusive or</span></td>
</tr>
</tbody>
</table><p><span>Add to </span><a href="https://eel.is/c++draft/atomics.syn" target="_blank" rel="noopener"><span>[atomics.syn]</span></a><span>:</span></p><pre><code>namespace std {
// [atomics.nonmembers], non-member functions
...
<ins>template&lt;class T&gt;
 void atomic_compare_store(atomic&lt;T&gt;*,               // freestanding
                           typename atomic&lt;T&gt;::value_type*,
                           typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_compare_store(volatile atomic&lt;T&gt;*,      // freestanding
                           typename atomic&lt;T&gt;::value_type*,
                           typename atomic&lt;T&gt;::value_type) noexcept;
                           
template&lt;class T&gt;
 void atomic_reduce_add(volatile atomic&lt;T&gt;*,         // freestanding
                        typename atomic&lt;T&gt;::difference_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_add(atomic&lt;T&gt;*,                  // freestanding
                        typename atomic&lt;T&gt;::difference_type) noexcept;   
template&lt;class T&gt;
 void atomic_reduce_add_explicit(volatile atomic&lt;T&gt;*,// freestanding
                                 typename atomic&lt;T&gt;::difference_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_add_explicit(atomic&lt;T&gt;*,         // freestanding
                                 typename atomic&lt;T&gt;::difference_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_sub(volatile atomic&lt;T&gt;*,         // freestanding
                       typename atomic&lt;T&gt;::difference_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_sub(atomic&lt;T&gt;*,                  // freestanding
                        typename atomic&lt;T&gt;::difference_type) noexcept;
template&lt;class T&gt; 
 void atomic_reduce_sub_explicit(volatile atomic&lt;T&gt;*,// freestanding
                                 typename atomic&lt;T&gt;::difference_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_sub_explicit(atomic&lt;T&gt;*,         // freestanding
                                 typename atomic&lt;T&gt;::difference_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_and(volatile atomic&lt;T&gt;*,         // freestanding
                        typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_and(atomic&lt;T&gt;*,                  // freestanding
                        typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_and_explicit(volatile atomic&lt;T&gt;*,// freestanding
                                 typename atomic&lt;T&gt;::value_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_and_explicit(atomic&lt;T&gt;*,         // freestanding
                                 typename atomic&lt;T&gt;::value_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_or(volatile atomic&lt;T&gt;*,          // freestanding
                      typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_or(atomic&lt;T&gt;*,                   // freestanding
                       typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_or_explicit(volatile atomic&lt;T&gt;*, // freestanding
                               typename atomic&lt;T&gt;::value_type,
                               memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_or_explicit(atomic&lt;T&gt;*,          // freestanding
                                typename atomic&lt;T&gt;::value_type,
                                memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_xor(volatile atomic&lt;T&gt;*,         // freestanding
                        typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_xor(atomic&lt;T&gt;*,                  // freestanding 
                        typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_xor_explicit(volatile atomic&lt;T&gt;*,// freestanding
                                 typename atomic&lt;T&gt;::value_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_xor_explicit(atomic&lt;T&gt;*,         // freestanding
                                 typename atomic&lt;T&gt;::value_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_max(volatile atomic&lt;T&gt;*,         // freestanding
                        typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_max(atomic&lt;T&gt;*,                  // freestanding
                        typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_max_explicit(volatile atomic&lt;T&gt;*, // freestanding
                                 typename atomic&lt;T&gt;::value_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_max_explicit(atomic&lt;T&gt;*,          // freestanding
                                 typename atomic&lt;T&gt;::value_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_min(volatile atomic&lt;T&gt;*,          // freestanding
                       typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_min(atomic&lt;T&gt;*,                   // freestanding
                        typename atomic&lt;T&gt;::value_type) noexcept;
template&lt;class T&gt;
 void atomic_reduce_min_explicit(volatile atomic&lt;T&gt;*, // freestanding
                                 typename atomic&lt;T&gt;::value_type,
                                 memory_order) noexcept;
template&lt;class T&gt;
 void atomic_reduce_min_explicit(atomic&lt;T&gt;*,          // freestanding
                                 typename atomic&lt;T&gt;::value_type,
                                 memory_order) noexcept;</ins>
}</code></pre><p><span>Add to </span><a href="https://eel.is/c++draft/atomics.ref.generic" target="_blank" rel="noopener"><span>[atomics.ref.generic]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic_ref {
    ...
  public:
    ...
    bool compare_exchange_strong(T&amp;, T,
                                 memory_order = memory_order::seq_cst) const noexcept;
                                 
    <ins>void compare_store(T, T, memory_order = memory_order::seq_cst) const noexcept;</ins>
    // ...
  };
}</code></pre><p><span>Add to </span><a href="https://eel.is/c++draft/atomics.ref.ops" target="_blank" rel="noopener"><span>[atomics.ref.ops]</span></a><span>:</span></p><pre><code><ins>void compare_store(T expected, T desired,</ins>
                   <ins>memory_order order = memory_order::seq_cst) const noexcept;</ins></code></pre><ul>
<li><ins><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is </span><code>memory_order::relaxed</code><span>, </span><code>memory_order::release</code><span>, or </span><code>memory_order::seq_cst</code><span>.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Atomically compares the value representation of the value referenced by </span><code>*ptr</code><span> for equality with the value in </span><code>expected</code><span>, and if </span><code>true</code><span>, replaces the value pointed to by </span><code>*ptr</code><span> with that in </span><code>desired</code><span>. If and only if the comparison is </span><code>true</code><span>, memory is affected according to the value of </span><code>order</code><span>; otherwise, memory is not affected. This operation is an atomic read-modify-write operations ([intro.races]) and an atomic reduction operations on the value referenced by </span><code>*ptr</code><span>.</span></ins><br>
</li>
</ul><p><span>Add to </span><a href="https://eel.is/c++draft/atomics.ref.int" target="_blank" rel="noopener"><span>[atomics.ref.int]</span></a><span>:</span></p><pre><code>
namespace std {
  template&lt;&gt; struct atomic_ref&lt;integral-type&gt; {
    ...
   public:
    ...
    <ins>void compare_store(integral-type expected, integral-type desired,</ins>
                    <ins>memory_order order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_add(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_sub(integral-type</ins>,
                   <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_and(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_or(integral-type,</ins>
                   <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_xor(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_max(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_min(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
  
}</code></pre><pre><code><ins>void reduce_&lt;key&gt;(integral-type operand,</ins> 
                  <ins>memory_order order = memory_order_seq_cst) const noexcept;</ins></code></pre><ul>
<li><ins><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is </span><code>memory_order_relaxed</code><span>, </span><code>memory_order_release</code><span>, or </span><code>memory_order_seq_cst</code><span>.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Atomically replaces the value referenced by </span><code>*ptr</code><span> with the result of the computation applied to the value referenced by </span><code>*ptr</code><span> and the given </span><code>operand</code><span>. Memory is affected according to the value of </span><code>order</code><span>. These operations are atomic read-modify-write operations ([intro.races]) </span><strong><span>and atomic reduction operations</span></strong><span>.</span></ins></li>
<li><ins><em><span>Remarks</span></em><span>: Except for </span><code>reduce_max</code><span> and </span><code>reduce_min</code><span>, for signed integer types, the result is as if the object value and parameters were converted to their corresponding unsigned types, the computation performed on those types, and the result converted back to the signed type.</span><br>
<span>[Note 2: There are no undefined results arising from the computation. — end note]</span></ins><br>
<ins><span>[Note 3: A lock-free atomic reduction operation is not vectorization-unsafe ([algorithms.parallel.defns]). — end note]</span></ins><br>
<ins><span>For </span><code>reduce_max</code><span> and </span><code>reduce_min</code><span>, the maximum and minimum computation is performed as if by </span><code>max</code><span> and </span><code>min</code><span> algorithms ([alg.min.max]), respectively, with the object value and the first parameter as the arguments.</span></ins></li>
</ul><p><span>Add to </span><a href="" target="_blank" rel="noopener"><span>[atomics.ref.float]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic_ref&lt;floating-point-type&gt; {
    ...
  public:
    ... 
    <ins>void compare_store(floating-point-type expected, floating-point-type desired,</ins>
                       <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_add(floating-point-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_sub(floating-point-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
  };
}</code></pre><p><bdi><strong><span>Review note</span></strong><span>: add reduce_minimum, _minimum_num, _maximum, and _maximum_num once 3008 is merged.</span></bdi></p><pre><code><ins>void reduce_key(floating-point-type operand,</ins>
                <ins>memory_order order = memory_order::seq_cst) const noexcept;</ins></code></pre><ul>
<li><ins><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is </span><code>memory_order_relaxed</code><span>, </span><code>memory_order_release</code><span>, or </span><code>memory_order_seq_cst</code><span>.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Atomically replaces the value referenced by </span><code>*ptr</code><span> with the result of the computation applied to the value referenced by </span><code>*ptr</code><span> and the given </span><code>operand</code><span>. Memory is affected according to the value of </span><code>order</code><span>. These operations are atomic read-modify-write operations ([intro.races]) </span><strong><span>and atomic reduction operations</span></strong><span>.</span></ins></li>
<li><ins><em><span>Remarks</span></em><span>: If the result is not a representable value for its type ([expr.pre]), the result is unspecified, but the operations otherwise have no undefined behavior. Atomic arithmetic operations on floating-point-type should conform to the </span><code>std::numeric_limits&lt;floating-point-type&gt;</code><span> traits associated with the floating-point type ([limits.syn]). The floating-point environment ([cfenv]) for atomic arithmetic operations on floating-point-type may be different than the calling thread's floating-point environment.</span></ins></li>
<li><ins><span>[Note 3: A lock-free atomic reduction operation is not vectorization-unsafe ([algorithms.parallel.defns]). — end note]</span></ins></li>
</ul><p><span>Add to </span><a href="https://eel.is/c++draft/atomics.ref.generic#atomics.ref.pointer" target="_blank" rel="noopener"><span>[atomics.ref.pointer]</span></a><span>:</span></p><pre><code>namespace std {
 template&lt;class T&gt; struct atomic_ref&lt;T*&gt; {
    ...
  public:
    ...
    <ins>void compare_store(T* expected, T* desired,</ins>
                       <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>

    <ins>void reduce_add(difference_type,</ins>
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_sub(difference_type,</ins> 
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_max(T*,</ins>
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
    <ins>void reduce_min(T*,</ins>
                    <ins>memory_order = memory_order::seq_cst) const noexcept;</ins>
  };
}</code></pre><pre><code><ins>void reduce_key(difference_type operand,</ins>
                <ins>memory_order order = memory_order::seq_cst) const noexcept;</ins></code></pre><ul>
<li><ins><em><span>Mandates</span></em><span>: </span><code>T</code><span> is a complete object type.</span></ins><span>ins&gt;</span></li>
<li><ins><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is </span><code>memory_order_relaxed</code><span>, </span><code>memory_order_release</code><span>, or </span><code>memory_order_seq_cst</code><span>.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Atomically replaces the value referenced by </span><code>*ptr</code><span> with the result of the computation applied to the value referenced by </span><code>*ptr</code><span> and the given operand. Memory is affected according to the value of order. These operations are atomic read-modify-write operations ([intro.races]) </span><strong><span>and atomic reduction operations</span></strong><span>.</span></ins></li>
<li><ins><em><span>Remarks</span></em><span>: The result may be an undefined address, but the operations otherwise have no undefined behavior.</span><br>
<span>For </span><code>fetch_max</code><span> and </span><code>fetch_min</code><span>, the maximum and minimum computation is performed as if by </span><code>max</code><span> and </span><code>min</code><span> algorithms ([alg.min.max]), respectively, with the object value and the first parameter as the arguments.</span><br>
<span>[Note 1: If the pointers point to different complete objects (or subobjects thereof), the </span><code>&lt;</code><span> operator does not establish a strict weak ordering (Table 29, [expr.rel]). — end note]</span></ins><br>
<ins><span>[Note 2: A lock-free atomic reduction operation is not vectorization-unsafe ([algorithms.parallel.defns]). — end note]</span></ins></li>
</ul><p><span>Add to </span><a href="https://eel.is/c++draft/atomics.types.generic.general" target="_blank" rel="noopener"><span>[atomics.types.generic.general]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic {
    
    <ins>void compare_store(T, T, memory_order) volatile noexcept;</ins>
    <ins>void compare_store(T, T, memory_order) noexcept;</ins>

  };
}</code></pre><p><span>Add to </span><a href="https://eel.is/c++draft/atomics.types.operations" target="_blank" rel="noopener"><span>[atomics.types.operations]</span></a><span>:</span></p><pre><code><ins>void compare_store(T expected, T desired,</ins> 
                   <ins>memory_order order = memory_order::seq_cst) const noexcept;</ins></code></pre><ul>
<li><ins><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is </span><code>memory_order::relaxed</code><span>, </span><code>memory_order::release</code><span>, or </span><code>memory_order::seq_cst</code><span>.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Atomically compares the value representation of the value pointed to by </span><code>this</code><span> for equality with that of </span><code>expected</code><span>, and if </span><code>true</code><span>, replaces the value pointed to by </span><code>this</code><span> with that in </span><code>desired</code><span>. If and only if the comparison is </span><code>true</code><span>, memory is affected according to the value of </span><code>order</code><span>; otherwise, memory is not affected. This operation is an atomic read-modify-write operations ([intro.races]) and an atomic reduction operations on the memory pointed to by </span><code>this</code><span>.</span></ins><br>
</li>
</ul><p><span>Add to </span><a href="https://eel.is/c++draft/atomics.types.int" target="_blank" rel="noopener"><span>[atomics.types.int]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic&lt;integral-type&gt; {
    ...
    
    <ins>void compare_store(integral-type, integral-type,</ins>
                       <ins>memory_order,) volatile noexcept;</ins>
    <ins>void compare_store(integral-type, integral-type,</ins>
                       <ins>memory_order) noexcept;</ins>

    <ins>void reduce_add(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_add(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
    <ins>void reduce_sub(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_sub(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
    <ins>void reduce_and(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_and(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
    <ins>void reduce_or(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_or(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
    <ins>void reduce_xor(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_xor(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
    <ins>void reduce_max(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_max(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
    <ins>void reduce_min(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_min(integral-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) noexcept;</ins>

  };
}</code></pre><pre><code><ins>void reduce_&lt;key&gt;(integral-type operand,</ins> 
          <ins>memory_order order = memory_order_seq_cst) volatile noexcept;</ins>
<ins>void reduce_&lt;key&gt;(integral-type operand,</ins> 
          <ins>memory_order order = memory_order_seq_cst) noexcept;</ins></code></pre><ul>
<li><ins><em><span>Constraints</span></em><span>: For the </span><code>volatile</code><span> overload of this function, </span><code>is_always_lock_free</code><span> is true.</span></ins></li>
<li><ins><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is </span><code>memory_order_relaxed</code><span>, </span><code>memory_order_release</code><span>, or </span><code>memory_order_seq_cst</code><span>.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Atomically replaces the value pointed to by </span><code>this</code><span> with the result of the computation applied to the value pointed to by </span><code>this</code><span> and the given operand. Memory is affected according to the value of </span><code>order</code><span>. These operations are atomic read-modify-write operations ([intro.multithread]) </span><strong><span>and atomic reduction operations</span></strong><span>.</span></ins></li>
<li><ins><em><span>Remarks</span></em><span>: Except for </span><code>reduce_max</code><span> and </span><code>reduce_min</code><span>, for signed integer types the result is as if the object value and parameters were converted to their corresponding unsigned types, the computation performed on those types, and the result converted back to the signed type.</span><br>
<span>[Note 2: There are no undefined results arising from the computation. — end note]</span></ins></li>
<li><ins><span>[Note 3: A lock-free atomic reduction operation is not vectorization-unsafe ([algorithms.parallel.defns]). — end note]</span></ins><br>
<ins><span>For </span><code>reduce_max</code><span> and </span><code>reduce_min</code><span>, the maximum and minimum computation is performed as if by </span><code>max</code><span> and </span><code>min</code><span> algorithms ([alg.min.max]), respectively, with the object value and the first parameter as the arguments.</span></ins></li>
</ul><p><span>Add to </span><a href="https://eel.is/c++draft/atomics.types.float" target="_blank" rel="noopener"><span>[atomics.types.float]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;&gt; struct atomic&lt;floating-point-type&gt; {
    ...
    
    <ins>void compare_store(floating-point-type, floating-point-type,</ins>
                       <ins>memory_order, memory_order) volatile noexcept;</ins>
    <ins>void compare_store(floating-point-type&amp;, floating-point-type,</ins>
                       <ins>memory_order, memory_order) noexcept;</ins>

    <ins>void reduce_add(floating-point-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_add(floating-point-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
    <ins>void reduce_sub(floating-point-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_sub(floating-point-type,</ins>
                    <ins>memory_order = memory_order::seq_cst) noexcept;</ins>

  };
}</code></pre><p><bdi><strong><span>Review note</span></strong><span>: add reduce_minimum, _minimum_num, _maximum, and _maximum_num once 3008 is merged.</span></bdi></p><pre><code><ins>void reduce_key(T operand,</ins>
      <ins>memory_order order = memory_order::seq_cst) volatile noexcept;</ins>
<ins>void reduce_key(T operand,</ins>
      <ins>memory_order order = memory_order::seq_cst) noexcept;</ins></code></pre><ul>
<li><ins><em><span>Constraints</span></em><span>: For the </span><code>volatile</code><span> overload of this function, </span><code>is_always_lock_free</code><span> is true.</span></ins></li>
<li><ins><em><span>Preconditions</span></em><span>: </span><code>order</code><span> is </span><code>memory_order_relaxed</code><span>, </span><code>memory_order_release</code><span>, or </span><code>memory_order_seq_cst</code><span>.</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Atomically replaces the value pointed to by </span><code>this</code><span> with the result of the computation applied to the value pointed to by </span><code>this</code><span> and the given </span><code>operand</code><span>. Memory is affected according to the value of </span><code>order</code><span>. These operations are atomic read-modify-write operations ([intro.multithread]) </span><strong><span>and atomic reduction operations</span></strong><span>.</span></ins></li>
<li><ins><em><span>Remarks</span></em><span>: If the result is not a representable value for its type ([expr.pre]) the result is unspecified, but the operations otherwise have no undefined behavior. Atomic arithmetic operations on </span><code>floating-point-type</code><span> should conform to the </span><code>std::numeric_limits&lt;floating-point-type&gt;</code><span> traits associated with the floating-point type ([limits.syn]). The floating-point environment ([cfenv]) for atomic arithmetic operations on </span><code>floating-point-type</code><span> may be different than the calling thread's floating-point environment.</span></ins></li>
</ul><p><span>Add to </span><a href="https://eel.is/c++draft/atomics.types.pointer" target="_blank" rel="noopener"><span>[atomics.types.pointer]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic&lt;T*&gt; {
    ...
    
    <ins>void compare_store(T*, T*,</ins>
            <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void compare_store(T*, T*,</ins>
            <ins>memory_order = memory_order::seq_cst) noexcept;</ins>

    <ins>void reduce_add(ptrdiff_t,</ins> 
      <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_add(ptrdiff_t,</ins> 
      <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
    <ins>void reduce_sub(ptrdiff_t,</ins> 
      <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_sub(ptrdiff_t,</ins> 
      <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
    <ins>void reduce_max(T*,</ins> 
      <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_max(T*,</ins> 
      <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
    <ins>void reduce_min(T*,</ins> 
      <ins>memory_order = memory_order::seq_cst) volatile noexcept;</ins>
    <ins>void reduce_min(T*,</ins> 
      <ins>memory_order = memory_order::seq_cst) noexcept;</ins>
  };
}</code></pre><pre><code><ins>void reduce_key(ptrdiff_t operand,</ins> 
     <ins>memory_order order = memory_order::seq_cst) volatile noexcept;</ins>
<ins>void reduce_key(ptrdiff_t operand,</ins>
     <ins>memory_order order = memory_order::seq_cst) noexcept;</ins></code></pre><ul>
<li><ins><em><span>Constraints</span></em><span>: For the </span><code>volatile</code><span> overload of this function, </span><code>is_always_lock_free</code><span> is true.</span></ins></li>
<li><ins><em><span>Mandates</span></em><span>: </span><code>T</code><span> is a complete object type.</span></ins><br>
<ins><span>[Note 1: Pointer arithmetic on void* or function pointers is ill-formed. — end note]</span></ins></li>
<li><ins><em><span>Effects</span></em><span>: Atomically replaces the value pointed to by this with the result of the computation applied to the value pointed to by </span><code>this</code><span> and the given operand. Memory is affected according to the value of </span><code>order</code><span>. These operations are atomic read-modify-write operations ([intro.multithread]).</span></ins></li>
<li><ins><em><span>Remarks</span></em><span>: The result may be an undefined address, but the operations otherwise have no undefined behavior.</span></ins><br>
<ins><span>For </span><code>reduce_max</code><span> and </span><code>reduce_min</code><span>, the maximum and minimum computation is performed as if by </span><code>max</code><span> and </span><code>min</code><span> algorithms ([alg.min.max]), respectively, with the object value and the first parameter as the arguments.</span></ins><br>
<ins><span>[Note 2: If the pointers point to different complete objects (or subobjects thereof), the </span><code>&lt;</code><span> operator does not establish a strict weak ordering (Table 29, [expr.rel]). — end note]</span></ins></li>
</ul><p><span>Add to </span><a href="https://eel.is/c++draft/util.smartptr.atomic.shared" target="_blank" rel="noopener"><span>[util.smartptr.atomic.shared]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic&lt;shared_ptr&lt;T&gt;&gt; {
    ...

    <ins>void compare_store(shared_ptr&lt;T&gt; expected, shared_ptr&lt;T&gt; desired,</ins>
      <ins>memory_order order = memory_order::seq_cst) noexcept;</ins>

  };
}</code></pre><p><span>Add to </span><a href="https://eel.is/c++draft/util.smartptr.atomic.weak" target="_blank" rel="noopener"><span>[util.smartptr.atomic.weak]</span></a><span>:</span></p><pre><code>namespace std {
  template&lt;class T&gt; struct atomic&lt;weak_ptr&lt;T&gt;&gt; {
    ...

    <ins>void compare_store(weak_ptr&lt;T&gt; expected, weak_ptr&lt;T&gt; desired,</ins>
      <ins>memory_order order = memory_order::seq_cst) noexcept;</ins>

  };
}</code></pre></div>
    <div class="ui-toc dropup unselectable hidden-print" style="display:none;">
        <div class="pull-right dropdown">
            <a id="tocLabel" class="ui-toc-label btn btn-default" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" title="Table of content">
                <i class="fa fa-bars"></i>
            </a>
            <ul id="ui-toc" class="ui-toc-dropdown dropdown-menu" aria-labelledby="tocLabel">
                <div class="toc"><ul class="nav">
<li class=""><a href="#Atomic-Reduction-Operations" title="Atomic Reduction Operations">Atomic Reduction Operations</a><ul class="nav">
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Motivation" title="Motivation">Motivation</a><ul class="nav">
<li><a href="#Hardware-Exposure" title="Hardware Exposure">Hardware Exposure</a></li>
<li><a href="#Performance" title="Performance">Performance</a></li>
<li><a href="#Functionality" title="Functionality">Functionality</a></li>
</ul>
</li>
<li><a href="#Design" title="Design">Design</a><ul class="nav">
<li><a href="#Implementation-impact" title="Implementation impact">Implementation impact</a></li>
<li><a href="#Design-Alternatives" title="Design Alternatives">Design Alternatives</a></li>
<li><a href="#Naming" title="Naming">Naming</a></li>
<li><a href="#Memory-Ordering" title="Memory Ordering">Memory Ordering</a></li>
<li><a href="#Formalization" title="Formalization">Formalization</a></li>
</ul>
</li>
<li class=""><a href="#Wording" title="Wording">Wording</a><ul class="nav">
<li><a href="#Forward-progress" title="Forward progress">Forward progress</a></li>
<li><a href="#No-acquire-sequences-support" title="No acquire sequences support">No acquire sequences support</a></li>
<li class=""><a href="#Atomic-Reduction-Operation-APIs" title="Atomic Reduction Operation APIs">Atomic Reduction Operation APIs</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
            </ul>
        </div>
    </div>
    <div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;"  >
        <div class="toc"><ul class="nav">
<li class=""><a href="#Atomic-Reduction-Operations" title="Atomic Reduction Operations">Atomic Reduction Operations</a><ul class="nav">
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Motivation" title="Motivation">Motivation</a><ul class="nav">
<li><a href="#Hardware-Exposure" title="Hardware Exposure">Hardware Exposure</a></li>
<li><a href="#Performance" title="Performance">Performance</a></li>
<li><a href="#Functionality" title="Functionality">Functionality</a></li>
</ul>
</li>
<li><a href="#Design" title="Design">Design</a><ul class="nav">
<li><a href="#Implementation-impact" title="Implementation impact">Implementation impact</a></li>
<li><a href="#Design-Alternatives" title="Design Alternatives">Design Alternatives</a></li>
<li><a href="#Naming" title="Naming">Naming</a></li>
<li><a href="#Memory-Ordering" title="Memory Ordering">Memory Ordering</a></li>
<li><a href="#Formalization" title="Formalization">Formalization</a></li>
</ul>
</li>
<li class=""><a href="#Wording" title="Wording">Wording</a><ul class="nav">
<li><a href="#Forward-progress" title="Forward progress">Forward progress</a></li>
<li><a href="#No-acquire-sequences-support" title="No acquire sequences support">No acquire sequences support</a></li>
<li class=""><a href="#Atomic-Reduction-Operation-APIs" title="Atomic Reduction Operation APIs">Atomic Reduction Operation APIs</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
    <script>
        var markdown = $(".markdown-body");
        //smooth all hash trigger scrolling
        function smoothHashScroll() {
            var hashElements = $("a[href^='#']").toArray();
            for (var i = 0; i < hashElements.length; i++) {
                var element = hashElements[i];
                var $element = $(element);
                var hash = element.hash;
                if (hash) {
                    $element.on('click', function (e) {
                        // store hash
                        var hash = this.hash;
                        if ($(hash).length <= 0) return;
                        // prevent default anchor click behavior
                        e.preventDefault();
                        // animate
                        $('body, html').stop(true, true).animate({
                            scrollTop: $(hash).offset().top
                        }, 100, "linear", function () {
                            // when done, add hash to url
                            // (default click behaviour)
                            window.location.hash = hash;
                        });
                    });
                }
            }
        }

        smoothHashScroll();
        var toc = $('.ui-toc');
        var tocAffix = $('.ui-affix-toc');
        var tocDropdown = $('.ui-toc-dropdown');
        //toc
        tocDropdown.click(function (e) {
            e.stopPropagation();
        });

        var enoughForAffixToc = true;

        function generateScrollspy() {
            $(document.body).scrollspy({
                target: ''
            });
            $(document.body).scrollspy('refresh');
            if (enoughForAffixToc) {
                toc.hide();
                tocAffix.show();
            } else {
                tocAffix.hide();
                toc.show();
            }
            $(document.body).scroll();
        }

        function windowResize() {
            //toc right
            var paddingRight = parseFloat(markdown.css('padding-right'));
            var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
            toc.css('right', right + 'px');
            //affix toc left
            var newbool;
            var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
            //for ipad or wider device
            if (rightMargin >= 133) {
                newbool = true;
                var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
                var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
                tocAffix.css('left', left + 'px');
            } else {
                newbool = false;
            }
            if (newbool != enoughForAffixToc) {
                enoughForAffixToc = newbool;
                generateScrollspy();
            }
        }
        $(window).resize(function () {
            windowResize();
        });
        $(document).ready(function () {
            windowResize();
            generateScrollspy();
        });

        //remove hash
        function removeHash() {
            window.location.hash = '';
        }

        var backtotop = $('.back-to-top');
        var gotobottom = $('.go-to-bottom');

        backtotop.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            if (scrollToTop)
                scrollToTop();
            removeHash();
        });
        gotobottom.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            if (scrollToBottom)
                scrollToBottom();
            removeHash();
        });

        var toggle = $('.expand-toggle');
        var tocExpand = false;

        checkExpandToggle();
        toggle.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            tocExpand = !tocExpand;
            checkExpandToggle();
        })

        function checkExpandToggle () {
            var toc = $('.ui-toc-dropdown .toc');
            var toggle = $('.expand-toggle');
            if (!tocExpand) {
                toc.removeClass('expand');
                toggle.text('Expand all');
            } else {
                toc.addClass('expand');
                toggle.text('Collapse all');
            }
        }

        function scrollToTop() {
            $('body, html').stop(true, true).animate({
                scrollTop: 0
            }, 100, "linear");
        }

        function scrollToBottom() {
            $('body, html').stop(true, true).animate({
                scrollTop: $(document.body)[0].scrollHeight
            }, 100, "linear");
        }
    </script>
</body>

</html>
