Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/js/src/jit/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 35 kB image not shown  

Quelle  GenerateAtomicOperations.py   Sprache: Python

 
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# This script generates jit/AtomicOperationsGenerated.h
#
# See the big comment in jit/AtomicOperations.h for an explanation.

import buildconfig

is_64bit = "JS_64BIT" in buildconfig.defines
cpu_arch = buildconfig.substs["TARGET_CPU"]
is_gcc = buildconfig.substs["CC_TYPE"] == "gcc"


def fmt_insn(s):
    return '"' + s + '\\n\\t"\n'


def gen_seqcst(fun_name):
    if cpu_arch in ("x86""x86_64"):
        return r"""
            INLINE_ATTR void %(fun_name)s() {
                asm volatile ("mfence\n\t" ::: "memory");
            }""" % {
            "fun_name": fun_name,
        }
    if cpu_arch == "aarch64":
        return r"""
            INLINE_ATTR void %(fun_name)s() {
                asm volatile ("dmb ish\n\t" ::: "memory");
            }""" % {
            "fun_name": fun_name,
        }
    if cpu_arch == "arm":
        return r"""
            INLINE_ATTR void %(fun_name)s() {
                asm volatile ("dmb sy\n\t" ::: "memory");
            }""" % {
            "fun_name": fun_name,
        }
    raise Exception("Unexpected arch")


def gen_load(fun_name, cpp_type, size, barrier):
    # NOTE: the assembly code must match the generated code in:
    # - CacheIRCompiler::emitAtomicsLoadResult
    # - LIRGenerator::visitLoadUnboxedScalar
    # - CodeGenerator::visitAtomicLoad64 (on 64-bit platforms)
    # - MacroAssembler::wasmLoad
    if cpu_arch in ("x86""x86_64"):
        insns = ""
        if size == 8:
            insns += fmt_insn("movb (%[arg]), %[res]")
        elif size == 16:
            insns += fmt_insn("movw (%[arg]), %[res]")
        elif size == 32:
            insns += fmt_insn("movl (%[arg]), %[res]")
        else:
            assert size == 64
            insns += fmt_insn("movq (%[arg]), %[res]")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(const %(cpp_type)s* arg) {
                %(cpp_type)s res;
                asm volatile (%(insns)s
                    : [res] "=r" (res)
                    : [arg] "r" (arg)
                    : "memory");
                return res;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    if cpu_arch == "aarch64":
        insns = ""
        if size == 8:
            insns += fmt_insn("ldrb %w[res], [%x[arg]]")
        elif size == 16:
            insns += fmt_insn("ldrh %w[res], [%x[arg]]")
        elif size == 32:
            insns += fmt_insn("ldr %w[res], [%x[arg]]")
        else:
            assert size == 64
            insns += fmt_insn("ldr %x[res], [%x[arg]]")
        if barrier:
            insns += fmt_insn("dmb ish")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(const %(cpp_type)s* arg) {
                %(cpp_type)s res;
                asm volatile (%(insns)s
                    : [res] "=r" (res)
                    : [arg] "r" (arg)
                    : "memory");
                return res;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    if cpu_arch == "arm":
        insns = ""
        if size == 8:
            insns += fmt_insn("ldrb %[res], [%[arg]]")
        elif size == 16:
            insns += fmt_insn("ldrh %[res], [%[arg]]")
        else:
            assert size == 32
            insns += fmt_insn("ldr %[res], [%[arg]]")
        if barrier:
            insns += fmt_insn("dmb sy")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(const %(cpp_type)s* arg) {
                %(cpp_type)s res;
                asm volatile (%(insns)s
                    : [res] "=r" (res)
                    : [arg] "r" (arg)
                    : "memory");
                return res;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    raise Exception("Unexpected arch")


def gen_store(fun_name, cpp_type, size, barrier):
    # NOTE: the assembly code must match the generated code in:
    # - CacheIRCompiler::emitAtomicsStoreResult
    # - LIRGenerator::visitStoreUnboxedScalar
    # - CodeGenerator::visitAtomicStore64 (on 64-bit platforms)
    # - MacroAssembler::wasmStore
    if cpu_arch in ("x86""x86_64"):
        insns = ""
        if size == 8:
            insns += fmt_insn("movb %[val], (%[addr])")
        elif size == 16:
            insns += fmt_insn("movw %[val], (%[addr])")
        elif size == 32:
            insns += fmt_insn("movl %[val], (%[addr])")
        else:
            assert size == 64
            insns += fmt_insn("movq %[val], (%[addr])")
        if barrier:
            insns += fmt_insn("mfence")
        return """
            INLINE_ATTR void %(fun_name)s(%(cpp_type)s* addr, %(cpp_type)s val) {
                asm volatile (%(insns)s
                    :
                    : [addr] "r" (addr), [val] "r"(val)
                    : "memory");
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    if cpu_arch == "aarch64":
        insns = ""
        if barrier:
            insns += fmt_insn("dmb ish")
        if size == 8:
            insns += fmt_insn("strb %w[val], [%x[addr]]")
        elif size == 16:
            insns += fmt_insn("strh %w[val], [%x[addr]]")
        elif size == 32:
            insns += fmt_insn("str %w[val], [%x[addr]]")
        else:
            assert size == 64
            insns += fmt_insn("str %x[val], [%x[addr]]")
        if barrier:
            insns += fmt_insn("dmb ish")
        return """
            INLINE_ATTR void %(fun_name)s(%(cpp_type)s* addr, %(cpp_type)s val) {
                asm volatile (%(insns)s
                    :
                    : [addr] "r" (addr), [val] "r"(val)
                    : "memory");
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    if cpu_arch == "arm":
        insns = ""
        if barrier:
            insns += fmt_insn("dmb sy")
        if size == 8:
            insns += fmt_insn("strb %[val], [%[addr]]")
        elif size == 16:
            insns += fmt_insn("strh %[val], [%[addr]]")
        else:
            assert size == 32
            insns += fmt_insn("str %[val], [%[addr]]")
        if barrier:
            insns += fmt_insn("dmb sy")
        return """
            INLINE_ATTR void %(fun_name)s(%(cpp_type)s* addr, %(cpp_type)s val) {
                asm volatile (%(insns)s
                    :
                    : [addr] "r" (addr), [val] "r"(val)
                    : "memory");
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    raise Exception("Unexpected arch")


def gen_exchange(fun_name, cpp_type, size):
    # NOTE: the assembly code must match the generated code in:
    # - MacroAssembler::atomicExchange
    # - MacroAssembler::atomicExchange64 (on 64-bit platforms)
    if cpu_arch in ("x86""x86_64"):
        # Request an input/output register for `val` so that we can simply XCHG it
        # with *addr.
        insns = ""
        if size == 8:
            insns += fmt_insn("xchgb %[val], (%[addr])")
        elif size == 16:
            insns += fmt_insn("xchgw %[val], (%[addr])")
        elif size == 32:
            insns += fmt_insn("xchgl %[val], (%[addr])")
        else:
            assert size == 64
            insns += fmt_insn("xchgq %[val], (%[addr])")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr, %(cpp_type)s val) {
                asm volatile (%(insns)s
                    : [val] "+r" (val)
                    : [addr] "r" (addr)
                    : "memory");
                return val;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    if cpu_arch == "aarch64":
        insns = ""
        insns += fmt_insn("dmb ish")
        insns += fmt_insn("0:")
        if size == 8:
            insns += fmt_insn("ldxrb %w[res], [%x[addr]]")
            insns += fmt_insn("stxrb %w[scratch], %w[val], [%x[addr]]")
        elif size == 16:
            insns += fmt_insn("ldxrh %w[res], [%x[addr]]")
            insns += fmt_insn("stxrh %w[scratch], %w[val], [%x[addr]]")
        elif size == 32:
            insns += fmt_insn("ldxr %w[res], [%x[addr]]")
            insns += fmt_insn("stxr %w[scratch], %w[val], [%x[addr]]")
        else:
            assert size == 64
            insns += fmt_insn("ldxr %x[res], [%x[addr]]")
            insns += fmt_insn("stxr %w[scratch], %x[val], [%x[addr]]")
        insns += fmt_insn("cbnz %w[scratch], 0b")
        insns += fmt_insn("dmb ish")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr, %(cpp_type)s val) {
                %(cpp_type)s res;
                uint32_t scratch;
                asm volatile (%(insns)s
                    : [res] "=&r"(res), [scratch] "=&r"(scratch)
                    : [addr] "r" (addr), [val] "r"(val)
                    : "memory""cc");
                return res;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    if cpu_arch == "arm":
        insns = ""
        insns += fmt_insn("dmb sy")
        insns += fmt_insn("0:")
        if size == 8:
            insns += fmt_insn("ldrexb %[res], [%[addr]]")
            insns += fmt_insn("strexb %[scratch], %[val], [%[addr]]")
        elif size == 16:
            insns += fmt_insn("ldrexh %[res], [%[addr]]")
            insns += fmt_insn("strexh %[scratch], %[val], [%[addr]]")
        else:
            assert size == 32
            insns += fmt_insn("ldrex %[res], [%[addr]]")
            insns += fmt_insn("strex %[scratch], %[val], [%[addr]]")
        insns += fmt_insn("cmp %[scratch], #1")
        insns += fmt_insn("beq 0b")
        insns += fmt_insn("dmb sy")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr, %(cpp_type)s val) {
                %(cpp_type)s res;
                uint32_t scratch;
                asm volatile (%(insns)s
                    : [res] "=&r"(res), [scratch] "=&r"(scratch)
                    : [addr] "r" (addr), [val] "r"(val)
                    : "memory""cc");
                return res;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    raise Exception("Unexpected arch")


def gen_cmpxchg(fun_name, cpp_type, size):
    # NOTE: the assembly code must match the generated code in:
    # - MacroAssembler::compareExchange
    # - MacroAssembler::compareExchange64
    if cpu_arch == "x86" and size == 64:
        # Use a +A constraint to load `oldval` into EDX:EAX as input/output.
        # `newval` is loaded into ECX:EBX.
        return r"""
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr,
                                             %(cpp_type)s oldval,
                                             %(cpp_type)s newval) {
                asm volatile ("lock; cmpxchg8b (%%[addr])\n\t"
                : "+A" (oldval)
                : [addr] "r" (addr),
                  "b" (uint32_t(newval & 0xffff'ffff)),
                  "c" (uint32_t(newval >> 32))
                : "memory""cc");
                return oldval;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
        }
    if cpu_arch == "arm" and size == 64:
        return r"""
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr,
                                             %(cpp_type)s oldval,
                                             %(cpp_type)s newval) {
                uint32_t oldval0 = oldval & 0xffff'ffff;
                uint32_t oldval1 = oldval >> 32;
                uint32_t newval0 = newval & 0xffff'ffff;
                uint32_t newval1 = newval >> 32;
                asm volatile (
                    "dmb sy\n\t"
                    "0: ldrexd r0, r1, [%%[addr]]\n\t"
                    "cmp r0, %%[oldval0]\n\t"
                    "bne 1f\n\t"
                    "cmp r1, %%[oldval1]\n\t"
                    "bne 1f\n\t"
                    "mov r2, %%[newval0]\n\t"
                    "mov r3, %%[newval1]\n\t"
                    "strexd r4, r2, r3, [%%[addr]]\n\t"
                    "cmp r4, #1\n\t"
                    "beq 0b\n\t"
                    "1: dmb sy\n\t"
                    "mov %%[oldval0], r0\n\t"
                    "mov %%[oldval1], r1\n\t"
                    : [oldval0] "+&r" (oldval0), [oldval1] "+&r"(oldval1)
                    : [addr] "r" (addr), [newval0] "r" (newval0), [newval1] "r" (newval1)
                    : "memory""cc""r0""r1""r2""r3""r4");
                return uint64_t(oldval0) | (uint64_t(oldval1) << 32);
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
        }
    if cpu_arch in ("x86""x86_64"):
        # Use a +a constraint to load `oldval` into RAX as input/output register.
        insns = ""
        if size == 8:
            insns += fmt_insn("lock; cmpxchgb %[newval], (%[addr])")
        elif size == 16:
            insns += fmt_insn("lock; cmpxchgw %[newval], (%[addr])")
        elif size == 32:
            insns += fmt_insn("lock; cmpxchgl %[newval], (%[addr])")
        else:
            assert size == 64
            insns += fmt_insn("lock; cmpxchgq %[newval], (%[addr])")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr,
                                             %(cpp_type)s oldval,
                                             %(cpp_type)s newval) {
                asm volatile (%(insns)s
                    : [oldval] "+a" (oldval)
                    : [addr] "r" (addr), [newval] "r" (newval)
                    : "memory""cc");
                return oldval;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    if cpu_arch == "aarch64":
        insns = ""
        insns += fmt_insn("dmb ish")
        insns += fmt_insn("0:")
        if size == 8:
            insns += fmt_insn("uxtb %w[scratch], %w[oldval]")
            insns += fmt_insn("ldxrb %w[res], [%x[addr]]")
            insns += fmt_insn("cmp %w[res], %w[scratch]")
            insns += fmt_insn("b.ne 1f")
            insns += fmt_insn("stxrb %w[scratch], %w[newval], [%x[addr]]")
        elif size == 16:
            insns += fmt_insn("uxth %w[scratch], %w[oldval]")
            insns += fmt_insn("ldxrh %w[res], [%x[addr]]")
            insns += fmt_insn("cmp %w[res], %w[scratch]")
            insns += fmt_insn("b.ne 1f")
            insns += fmt_insn("stxrh %w[scratch], %w[newval], [%x[addr]]")
        elif size == 32:
            insns += fmt_insn("mov %w[scratch], %w[oldval]")
            insns += fmt_insn("ldxr %w[res], [%x[addr]]")
            insns += fmt_insn("cmp %w[res], %w[scratch]")
            insns += fmt_insn("b.ne 1f")
            insns += fmt_insn("stxr %w[scratch], %w[newval], [%x[addr]]")
        else:
            assert size == 64
            insns += fmt_insn("mov %x[scratch], %x[oldval]")
            insns += fmt_insn("ldxr %x[res], [%x[addr]]")
            insns += fmt_insn("cmp %x[res], %x[scratch]")
            insns += fmt_insn("b.ne 1f")
            insns += fmt_insn("stxr %w[scratch], %x[newval], [%x[addr]]")
        insns += fmt_insn("cbnz %w[scratch], 0b")
        insns += fmt_insn("1: dmb ish")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr,
                                             %(cpp_type)s oldval,
                                             %(cpp_type)s newval) {
                %(cpp_type)s res, scratch;
                asm volatile (%(insns)s
                    : [res] "=&r" (res), [scratch] "=&r" (scratch)
                    : [addr] "r" (addr), [oldval] "r"(oldval), [newval] "r" (newval)
                    : "memory""cc");
                return res;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    if cpu_arch == "arm":
        insns = ""
        insns += fmt_insn("dmb sy")
        insns += fmt_insn("0:")
        if size == 8:
            insns += fmt_insn("uxtb %[scratch], %[oldval]")
            insns += fmt_insn("ldrexb %[res], [%[addr]]")
            insns += fmt_insn("cmp %[res], %[scratch]")
            insns += fmt_insn("bne 1f")
            insns += fmt_insn("strexb %[scratch], %[newval], [%[addr]]")
        elif size == 16:
            insns += fmt_insn("uxth %[scratch], %[oldval]")
            insns += fmt_insn("ldrexh %[res], [%[addr]]")
            insns += fmt_insn("cmp %[res], %[scratch]")
            insns += fmt_insn("bne 1f")
            insns += fmt_insn("strexh %[scratch], %[newval], [%[addr]]")
        else:
            assert size == 32
            insns += fmt_insn("mov %[scratch], %[oldval]")
            insns += fmt_insn("ldrex %[res], [%[addr]]")
            insns += fmt_insn("cmp %[res], %[scratch]")
            insns += fmt_insn("bne 1f")
            insns += fmt_insn("strex %[scratch], %[newval], [%[addr]]")
        insns += fmt_insn("cmp %[scratch], #1")
        insns += fmt_insn("beq 0b")
        insns += fmt_insn("1: dmb sy")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr,
                                             %(cpp_type)s oldval,
                                             %(cpp_type)s newval) {
                %(cpp_type)s res, scratch;
                asm volatile (%(insns)s
                    : [res] "=&r" (res), [scratch] "=&r" (scratch)
                    : [addr] "r" (addr), [oldval] "r"(oldval), [newval] "r" (newval)
                    : "memory""cc");
                return res;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    raise Exception("Unexpected arch")


def gen_fetchop(fun_name, cpp_type, size, op):
    # NOTE: the assembly code must match the generated code in:
    # - MacroAssembler::atomicFetchOp
    # - MacroAssembler::atomicFetchOp64 (on 64-bit platforms)
    if cpu_arch in ("x86""x86_64"):
        # The `add` operation can be optimized with XADD.
        if op == "add":
            insns = ""
            if size == 8:
                insns += fmt_insn("lock; xaddb %[val], (%[addr])")
            elif size == 16:
                insns += fmt_insn("lock; xaddw %[val], (%[addr])")
            elif size == 32:
                insns += fmt_insn("lock; xaddl %[val], (%[addr])")
            else:
                assert size == 64
                insns += fmt_insn("lock; xaddq %[val], (%[addr])")
            return """
                INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr, %(cpp_type)s val) {
                    asm volatile (%(insns)s
                        : [val] "+&r" (val)
                        : [addr] "r" (addr)
                        : "memory""cc");
                    return val;
                }""" % {
                "cpp_type": cpp_type,
                "fun_name": fun_name,
                "insns": insns,
            }
        # Use a +a constraint to ensure `res` is stored in RAX. This is required
        # for the CMPXCHG instruction.
        insns = ""
        if size == 8:
            insns += fmt_insn("movb (%[addr]), %[res]")
            insns += fmt_insn("0: movb %[res], %[scratch]")
            insns += fmt_insn("OPb %[val], %[scratch]")
            insns += fmt_insn("lock; cmpxchgb %[scratch], (%[addr])")
        elif size == 16:
            insns += fmt_insn("movw (%[addr]), %[res]")
            insns += fmt_insn("0: movw %[res], %[scratch]")
            insns += fmt_insn("OPw %[val], %[scratch]")
            insns += fmt_insn("lock; cmpxchgw %[scratch], (%[addr])")
        elif size == 32:
            insns += fmt_insn("movl (%[addr]), %[res]")
            insns += fmt_insn("0: movl %[res], %[scratch]")
            insns += fmt_insn("OPl %[val], %[scratch]")
            insns += fmt_insn("lock; cmpxchgl %[scratch], (%[addr])")
        else:
            assert size == 64
            insns += fmt_insn("movq (%[addr]), %[res]")
            insns += fmt_insn("0: movq %[res], %[scratch]")
            insns += fmt_insn("OPq %[val], %[scratch]")
            insns += fmt_insn("lock; cmpxchgq %[scratch], (%[addr])")
        insns = insns.replace("OP", op)
        insns += fmt_insn("jnz 0b")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr, %(cpp_type)s val) {
                %(cpp_type)s res, scratch;
                asm volatile (%(insns)s
                    : [res] "=&a" (res), [scratch] "=&r" (scratch)
                    : [addr] "r" (addr), [val] "r"(val)
                    : "memory""cc");
                return res;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    if cpu_arch == "aarch64":
        insns = ""
        insns += fmt_insn("dmb ish")
        insns += fmt_insn("0:")
        if size == 8:
            insns += fmt_insn("ldxrb %w[res], [%x[addr]]")
            insns += fmt_insn("OP %x[scratch1], %x[res], %x[val]")
            insns += fmt_insn("stxrb %w[scratch2], %w[scratch1], [%x[addr]]")
        elif size == 16:
            insns += fmt_insn("ldxrh %w[res], [%x[addr]]")
            insns += fmt_insn("OP %x[scratch1], %x[res], %x[val]")
            insns += fmt_insn("stxrh %w[scratch2], %w[scratch1], [%x[addr]]")
        elif size == 32:
            insns += fmt_insn("ldxr %w[res], [%x[addr]]")
            insns += fmt_insn("OP %x[scratch1], %x[res], %x[val]")
            insns += fmt_insn("stxr %w[scratch2], %w[scratch1], [%x[addr]]")
        else:
            assert size == 64
            insns += fmt_insn("ldxr %x[res], [%x[addr]]")
            insns += fmt_insn("OP %x[scratch1], %x[res], %x[val]")
            insns += fmt_insn("stxr %w[scratch2], %x[scratch1], [%x[addr]]")
        cpu_op = op
        if cpu_op == "or":
            cpu_op = "orr"
        if cpu_op == "xor":
            cpu_op = "eor"
        insns = insns.replace("OP", cpu_op)
        insns += fmt_insn("cbnz %w[scratch2], 0b")
        insns += fmt_insn("dmb ish")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr, %(cpp_type)s val) {
                %(cpp_type)s res;
                uintptr_t scratch1, scratch2;
                asm volatile (%(insns)s
                    : [res] "=&r" (res), [scratch1] "=&r" (scratch1), [scratch2] "=&r"(scratch2)
                    : [addr] "r" (addr), [val] "r"(val)
                    : "memory""cc");
                return res;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    if cpu_arch == "arm":
        insns = ""
        insns += fmt_insn("dmb sy")
        insns += fmt_insn("0:")
        if size == 8:
            insns += fmt_insn("ldrexb %[res], [%[addr]]")
            insns += fmt_insn("OP %[scratch1], %[res], %[val]")
            insns += fmt_insn("strexb %[scratch2], %[scratch1], [%[addr]]")
        elif size == 16:
            insns += fmt_insn("ldrexh %[res], [%[addr]]")
            insns += fmt_insn("OP %[scratch1], %[res], %[val]")
            insns += fmt_insn("strexh %[scratch2], %[scratch1], [%[addr]]")
        else:
            assert size == 32
            insns += fmt_insn("ldrex %[res], [%[addr]]")
            insns += fmt_insn("OP %[scratch1], %[res], %[val]")
            insns += fmt_insn("strex %[scratch2], %[scratch1], [%[addr]]")
        cpu_op = op
        if cpu_op == "or":
            cpu_op = "orr"
        if cpu_op == "xor":
            cpu_op = "eor"
        insns = insns.replace("OP", cpu_op)
        insns += fmt_insn("cmp %[scratch2], #1")
        insns += fmt_insn("beq 0b")
        insns += fmt_insn("dmb sy")
        return """
            INLINE_ATTR %(cpp_type)s %(fun_name)s(%(cpp_type)s* addr, %(cpp_type)s val) {
                %(cpp_type)s res;
                uintptr_t scratch1, scratch2;
                asm volatile (%(insns)s
                    : [res] "=&r" (res), [scratch1] "=&r" (scratch1), [scratch2] "=&r"(scratch2)
                    : [addr] "r" (addr), [val] "r"(val)
                    : "memory""cc");
                return res;
            }""" % {
            "cpp_type": cpp_type,
            "fun_name": fun_name,
            "insns": insns,
        }
    raise Exception("Unexpected arch")


def gen_pause(fun_name):
    if cpu_arch in ("x86""x86_64"):
        return r"""
            INLINE_ATTR void %(fun_name)s() {
                asm volatile ("pause" :::);
            }""" % {
            "fun_name": fun_name,
        }
    if cpu_arch == "aarch64":
        return r"""
            INLINE_ATTR void %(fun_name)s() {
                asm volatile ("isb" ::: "memory");
            }""" % {
            "fun_name": fun_name,
        }
    if cpu_arch == "arm":
        return r"""
            INLINE_ATTR void %(fun_name)s() {
                asm volatile ("yield" :::);
            }""" % {
            "fun_name": fun_name,
        }
    raise Exception("Unexpected arch")


def gen_copy(fun_name, cpp_type, size, unroll, direction):
    assert direction in ("down""up")
    offset = 0
    if direction == "up":
        offset = unroll - 1
    insns = ""
    for i in range(unroll):
        if cpu_arch in ("x86""x86_64"):
            if size == 1:
                insns += fmt_insn("movb OFFSET(%[src]), %[scratch]")
                insns += fmt_insn("movb %[scratch], OFFSET(%[dst])")
            elif size == 2:
                insns += fmt_insn("movw OFFSET(%[src]), %[scratch]")
                insns += fmt_insn("movw %[scratch], OFFSET(%[dst])")
            elif size == 4:
                insns += fmt_insn("movl OFFSET(%[src]), %[scratch]")
                insns += fmt_insn("movl %[scratch], OFFSET(%[dst])")
            else:
                assert size == 8
                insns += fmt_insn("movq OFFSET(%[src]), %[scratch]")
                insns += fmt_insn("movq %[scratch], OFFSET(%[dst])")
        elif cpu_arch == "aarch64":
            if size == 1:
                insns += fmt_insn("ldrb %w[scratch], [%x[src], OFFSET]")
                insns += fmt_insn("strb %w[scratch], [%x[dst], OFFSET]")
            elif size == 2:
                insns += fmt_insn("ldrh %w[scratch], [%x[src], OFFSET]")
                insns += fmt_insn("strh %w[scratch], [%x[dst], OFFSET]")
            elif size == 4:
                insns += fmt_insn("ldr %w[scratch], [%x[src], OFFSET]")
                insns += fmt_insn("str %w[scratch], [%x[dst], OFFSET]")
            else:
                assert size == 8
                insns += fmt_insn("ldr %x[scratch], [%x[src], OFFSET]")
                insns += fmt_insn("str %x[scratch], [%x[dst], OFFSET]")
        elif cpu_arch == "arm":
            if size == 1:
                insns += fmt_insn("ldrb %[scratch], [%[src], #OFFSET]")
                insns += fmt_insn("strb %[scratch], [%[dst], #OFFSET]")
            elif size == 2:
                insns += fmt_insn("ldrh %[scratch], [%[src], #OFFSET]")
                insns += fmt_insn("strh %[scratch], [%[dst], #OFFSET]")
            else:
                assert size == 4
                insns += fmt_insn("ldr %[scratch], [%[src], #OFFSET]")
                insns += fmt_insn("str %[scratch], [%[dst], #OFFSET]")
        else:
            raise Exception("Unexpected arch")
        insns = insns.replace("OFFSET", str(offset * size))

        if direction == "down":
            offset += 1
        else:
            offset -= 1

    return """
        INLINE_ATTR void %(fun_name)s(uint8_t* dst, const uint8_t* src) {
            %(cpp_type)s* dst_ = reinterpret_cast<%(cpp_type)s*>(dst);
            const %(cpp_type)s* src_ = reinterpret_cast<const %(cpp_type)s*>(src);
            %(cpp_type)s scratch;
            asm volatile (%(insns)s
                : [scratch] "=&r" (scratch)
                : [dst] "r" (dst_), [src] "r"(src_)
                : "memory");
        }""" % {
        "cpp_type": cpp_type,
        "fun_name": fun_name,
        "insns": insns,
    }


HEADER_TEMPLATE = """\
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef jit_AtomicOperationsGenerated_h
#define jit_AtomicOperationsGenerated_h

/* This file is generated by jit/GenerateAtomicOperations.py. Do not edit! */

#include "mozilla/Attributes.h"

namespace js {
namespace jit {

%(contents)s

} // namespace jit
} // namespace js

#endif // jit_AtomicOperationsGenerated_h
"""


def generate_atomics_header(c_out):
    contents = ""
    if cpu_arch in ("x86""x86_64""aarch64"or (
        cpu_arch == "arm" and int(buildconfig.substs["ARM_ARCH"]) >= 7
    ):
        contents += "#define JS_HAVE_GENERATED_ATOMIC_OPS 1"

        # `fence` performs a full memory barrier.
        contents += gen_seqcst("AtomicFenceSeqCst")

        contents += gen_load("AtomicLoad8SeqCst""uint8_t", 8, True)
        contents += gen_load("AtomicLoad16SeqCst""uint16_t", 16, True)
        contents += gen_load("AtomicLoad32SeqCst""uint32_t", 32, True)
        if is_64bit:
            contents += gen_load("AtomicLoad64SeqCst""uint64_t", 64, True)

        # These are access-atomic up to sizeof(uintptr_t).
        contents += gen_load("AtomicLoad8Unsynchronized""uint8_t", 8, False)
        contents += gen_load("AtomicLoad16Unsynchronized""uint16_t", 16, False)
        contents += gen_load("AtomicLoad32Unsynchronized""uint32_t", 32, False)
        if is_64bit:
            contents += gen_load("AtomicLoad64Unsynchronized""uint64_t", 64, False)

        contents += gen_store("AtomicStore8SeqCst""uint8_t", 8, True)
        contents += gen_store("AtomicStore16SeqCst""uint16_t", 16, True)
        contents += gen_store("AtomicStore32SeqCst""uint32_t", 32, True)
        if is_64bit:
            contents += gen_store("AtomicStore64SeqCst""uint64_t", 64, True)

        # These are access-atomic up to sizeof(uintptr_t).
        contents += gen_store("AtomicStore8Unsynchronized""uint8_t", 8, False)
        contents += gen_store("AtomicStore16Unsynchronized""uint16_t", 16, False)
        contents += gen_store("AtomicStore32Unsynchronized""uint32_t", 32, False)
        if is_64bit:
            contents += gen_store("AtomicStore64Unsynchronized""uint64_t", 64, False)

        # `exchange` takes a cell address and a value.  It stores it in the cell and
        # returns the value previously in the cell.
        contents += gen_exchange("AtomicExchange8SeqCst""uint8_t", 8)
        contents += gen_exchange("AtomicExchange16SeqCst""uint16_t", 16)
        contents += gen_exchange("AtomicExchange32SeqCst""uint32_t", 32)
        if is_64bit:
            contents += gen_exchange("AtomicExchange64SeqCst""uint64_t", 64)

        # `cmpxchg` takes a cell address, an expected value and a replacement value.
        # If the value in the cell equals the expected value then the replacement value
        # is stored in the cell.  It always returns the value previously in the cell.
        contents += gen_cmpxchg("AtomicCmpXchg8SeqCst""uint8_t", 8)
        contents += gen_cmpxchg("AtomicCmpXchg16SeqCst""uint16_t", 16)
        contents += gen_cmpxchg("AtomicCmpXchg32SeqCst""uint32_t", 32)
        contents += gen_cmpxchg("AtomicCmpXchg64SeqCst""uint64_t", 64)

        # `add` adds a value atomically to the cell and returns the old value in the
        # cell.  (There is no `sub`; just add the negated value.)
        contents += gen_fetchop("AtomicAdd8SeqCst""uint8_t", 8, "add")
        contents += gen_fetchop("AtomicAdd16SeqCst""uint16_t", 16, "add")
        contents += gen_fetchop("AtomicAdd32SeqCst""uint32_t", 32, "add")
        if is_64bit:
            contents += gen_fetchop("AtomicAdd64SeqCst""uint64_t", 64, "add")

        # `and` bitwise-ands a value atomically into the cell and returns the old value
        # in the cell.
        contents += gen_fetchop("AtomicAnd8SeqCst""uint8_t", 8, "and")
        contents += gen_fetchop("AtomicAnd16SeqCst""uint16_t", 16, "and")
        contents += gen_fetchop("AtomicAnd32SeqCst""uint32_t", 32, "and")
        if is_64bit:
            contents += gen_fetchop("AtomicAnd64SeqCst""uint64_t", 64, "and")

        # `or` bitwise-ors a value atomically into the cell and returns the old value
        # in the cell.
        contents += gen_fetchop("AtomicOr8SeqCst""uint8_t", 8, "or")
        contents += gen_fetchop("AtomicOr16SeqCst""uint16_t", 16, "or")
        contents += gen_fetchop("AtomicOr32SeqCst""uint32_t", 32, "or")
        if is_64bit:
            contents += gen_fetchop("AtomicOr64SeqCst""uint64_t", 64, "or")

        # `xor` bitwise-xors a value atomically into the cell and returns the old value
        # in the cell.
        contents += gen_fetchop("AtomicXor8SeqCst""uint8_t", 8, "xor")
        contents += gen_fetchop("AtomicXor16SeqCst""uint16_t", 16, "xor")
        contents += gen_fetchop("AtomicXor32SeqCst""uint32_t", 32, "xor")
        if is_64bit:
            contents += gen_fetchop("AtomicXor64SeqCst""uint64_t", 64, "xor")

        # Pause or yield instruction.
        contents += gen_pause("AtomicPause")

        # See comment in jit/AtomicOperations-shared-jit.cpp for an explanation.
        wordsize = 8 if is_64bit else 4
        words_in_block = 8
        blocksize = words_in_block * wordsize

        contents += gen_copy(
            "AtomicCopyUnalignedBlockDownUnsynchronized",
            "uint8_t",
            1,
            blocksize,
            "down",
        )
        contents += gen_copy(
            "AtomicCopyUnalignedBlockUpUnsynchronized""uint8_t", 1, blocksize, "up"
        )

        contents += gen_copy(
            "AtomicCopyUnalignedWordDownUnsynchronized""uint8_t", 1, wordsize, "down"
        )
        contents += gen_copy(
            "AtomicCopyUnalignedWordUpUnsynchronized""uint8_t", 1, wordsize, "up"
        )

        contents += gen_copy(
            "AtomicCopyBlockDownUnsynchronized",
            "uintptr_t",
            wordsize,
            words_in_block,
            "down",
        )
        contents += gen_copy(
            "AtomicCopyBlockUpUnsynchronized",
            "uintptr_t",
            wordsize,
            words_in_block,
            "up",
        )

        contents += gen_copy(
            "AtomicCopyWordUnsynchronized""uintptr_t", wordsize, 1, "down"
        )
        contents += gen_copy("AtomicCopy32Unsynchronized""uint32_t", 4, 1, "down")
        contents += gen_copy("AtomicCopy16Unsynchronized""uint16_t", 2, 1, "down")
        contents += gen_copy("AtomicCopy8Unsynchronized""uint8_t", 1, 1, "down")

        contents += "\n"
        contents += (
            "constexpr size_t JS_GENERATED_ATOMICS_BLOCKSIZE = "
            + str(blocksize)
            + ";\n"
        )
        contents += (
            "constexpr size_t JS_GENERATED_ATOMICS_WORDSIZE = " + str(wordsize) + ";\n"
        )

        # Work around a GCC issue on 32-bit x86 by adding MOZ_NEVER_INLINE.
        # See bug 1756347.
        if is_gcc and cpu_arch == "x86":
            contents = contents.replace("INLINE_ATTR""MOZ_NEVER_INLINE inline")
        else:
            contents = contents.replace("INLINE_ATTR""inline")

    c_out.write(
        HEADER_TEMPLATE
        % {
            "contents": contents,
        }
    )

Messung V0.5
C=95 H=97 G=95

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.