/* Copyright (C) 2022-2023 Free Software Foundation, Inc. This file is part of the GNU Atomic Library (libatomic). Libatomic is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Libatomic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ .arch armv8-a+lse #define ENTRY(name) \ .global name; \ .hidden name; \ .type name,%function; \ .p2align 4; \ name: \ .cfi_startproc; \ hint 34 // bti c #define END(name) \ .cfi_endproc; \ .size name, .-name; #define res0 x0 #define res1 x1 #define in0 x2 #define in1 x3 #define tmp0 x6 #define tmp1 x7 #define exp0 x8 #define exp1 x9 #ifdef __AARCH64EB__ # define reslo x1 # define reshi x0 # define inlo x3 # define inhi x2 # define tmplo x7 # define tmphi x6 #else # define reslo x0 # define reshi x1 # define inlo x2 # define inhi x3 # define tmplo x6 # define tmphi x7 #endif #define RELAXED 0 #define CONSUME 1 #define ACQUIRE 2 #define RELEASE 3 #define ACQ_REL 4 #define SEQ_CST 5 ENTRY (libat_load_16_i1) cbnz w1, 1f /* RELAXED. */ ldp res0, res1, [x0] ret 1: cmp w1, SEQ_CST b.eq 2f /* ACQUIRE/CONSUME (Load-AcquirePC semantics). */ ldp res0, res1, [x0] dmb ishld ret /* SEQ_CST. */ 2: ldar tmp0, [x0] /* Block reordering with Store-Release instr. */ ldp res0, res1, [x0] dmb ishld ret END (libat_load_16_i1) ENTRY (libat_store_16_i1) cbnz w4, 1f /* RELAXED. */ stp in0, in1, [x0] ret /* RELEASE/SEQ_CST. */ 1: ldaxp xzr, tmp0, [x0] stlxp w4, in0, in1, [x0] cbnz w4, 1b ret END (libat_store_16_i1) ENTRY (libat_exchange_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] stxp w4, in0, in1, [x5] cbnz w4, 1b ret 2: cmp w4, ACQUIRE b.hi 4f /* ACQUIRE/CONSUME. */ 3: ldaxp res0, res1, [x5] stxp w4, in0, in1, [x5] cbnz w4, 3b ret 4: cmp w4, RELEASE b.ne 6f /* RELEASE. */ 5: ldxp res0, res1, [x5] stlxp w4, in0, in1, [x5] cbnz w4, 5b ret /* ACQ_REL/SEQ_CST. */ 6: ldaxp res0, res1, [x5] stlxp w4, in0, in1, [x5] cbnz w4, 6b ret END (libat_exchange_16_i1) ENTRY (libat_compare_exchange_16_i1) ldp exp0, exp1, [x1] mov tmp0, exp0 mov tmp1, exp1 cbz w4, 2f cmp w4, RELEASE b.hs 3f /* ACQUIRE/CONSUME. */ caspa exp0, exp1, in0, in1, [x0] 0: cmp exp0, tmp0 ccmp exp1, tmp1, 0, eq bne 1f mov x0, 1 ret 1: stp exp0, exp1, [x1] mov x0, 0 ret /* RELAXED. */ 2: casp exp0, exp1, in0, in1, [x0] b 0b /* RELEASE. */ 3: b.hi 4f caspl exp0, exp1, in0, in1, [x0] b 0b /* ACQ_REL/SEQ_CST. */ 4: caspal exp0, exp1, in0, in1, [x0] b 0b END (libat_compare_exchange_16_i1) ENTRY (libat_fetch_add_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] adds tmplo, reslo, inlo adc tmphi, reshi, inhi stxp w4, tmp0, tmp1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] adds tmplo, reslo, inlo adc tmphi, reshi, inhi stlxp w4, tmp0, tmp1, [x5] cbnz w4, 2b ret END (libat_fetch_add_16_i1) ENTRY (libat_add_fetch_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] adds reslo, reslo, inlo adc reshi, reshi, inhi stxp w4, res0, res1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] adds reslo, reslo, inlo adc reshi, reshi, inhi stlxp w4, res0, res1, [x5] cbnz w4, 2b ret END (libat_add_fetch_16_i1) ENTRY (libat_fetch_sub_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] subs tmplo, reslo, inlo sbc tmphi, reshi, inhi stxp w4, tmp0, tmp1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] subs tmplo, reslo, inlo sbc tmphi, reshi, inhi stlxp w4, tmp0, tmp1, [x5] cbnz w4, 2b ret END (libat_fetch_sub_16_i1) ENTRY (libat_sub_fetch_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] subs reslo, reslo, inlo sbc reshi, reshi, inhi stxp w4, res0, res1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] subs reslo, reslo, inlo sbc reshi, reshi, inhi stlxp w4, res0, res1, [x5] cbnz w4, 2b ret END (libat_sub_fetch_16_i1) ENTRY (libat_fetch_or_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] orr tmp0, res0, in0 orr tmp1, res1, in1 stxp w4, tmp0, tmp1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] orr tmp0, res0, in0 orr tmp1, res1, in1 stlxp w4, tmp0, tmp1, [x5] cbnz w4, 2b ret END (libat_fetch_or_16_i1) ENTRY (libat_or_fetch_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] orr res0, res0, in0 orr res1, res1, in1 stxp w4, res0, res1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] orr res0, res0, in0 orr res1, res1, in1 stlxp w4, res0, res1, [x5] cbnz w4, 2b ret END (libat_or_fetch_16_i1) ENTRY (libat_fetch_and_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] and tmp0, res0, in0 and tmp1, res1, in1 stxp w4, tmp0, tmp1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] and tmp0, res0, in0 and tmp1, res1, in1 stlxp w4, tmp0, tmp1, [x5] cbnz w4, 2b ret END (libat_fetch_and_16_i1) ENTRY (libat_and_fetch_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] and res0, res0, in0 and res1, res1, in1 stxp w4, res0, res1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] and res0, res0, in0 and res1, res1, in1 stlxp w4, res0, res1, [x5] cbnz w4, 2b ret END (libat_and_fetch_16_i1) ENTRY (libat_fetch_xor_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] eor tmp0, res0, in0 eor tmp1, res1, in1 stxp w4, tmp0, tmp1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] eor tmp0, res0, in0 eor tmp1, res1, in1 stlxp w4, tmp0, tmp1, [x5] cbnz w4, 2b ret END (libat_fetch_xor_16_i1) ENTRY (libat_xor_fetch_16_i1) mov x5, x0 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] eor res0, res0, in0 eor res1, res1, in1 stxp w4, res0, res1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] eor res0, res0, in0 eor res1, res1, in1 stlxp w4, res0, res1, [x5] cbnz w4, 2b ret END (libat_xor_fetch_16_i1) ENTRY (libat_fetch_nand_16_i1) mov x5, x0 mvn in0, in0 mvn in1, in1 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] orn tmp0, in0, res0 orn tmp1, in1, res1 stxp w4, tmp0, tmp1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] orn tmp0, in0, res0 orn tmp1, in1, res1 stlxp w4, tmp0, tmp1, [x5] cbnz w4, 2b ret END (libat_fetch_nand_16_i1) ENTRY (libat_nand_fetch_16_i1) mov x5, x0 mvn in0, in0 mvn in1, in1 cbnz w4, 2f /* RELAXED. */ 1: ldxp res0, res1, [x5] orn res0, in0, res0 orn res1, in1, res1 stxp w4, res0, res1, [x5] cbnz w4, 1b ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: ldaxp res0, res1, [x5] orn res0, in0, res0 orn res1, in1, res1 stlxp w4, res0, res1, [x5] cbnz w4, 2b ret END (libat_nand_fetch_16_i1) ENTRY (libat_test_and_set_16_i1) mov w2, 1 cbnz w1, 2f /* RELAXED. */ swpb w0, w2, [x0] ret /* ACQUIRE/CONSUME/RELEASE/ACQ_REL/SEQ_CST. */ 2: swpalb w0, w2, [x0] ret END (libat_test_and_set_16_i1) /* GNU_PROPERTY_AARCH64_* macros from elf.h for use in asm code. */ #define FEATURE_1_AND 0xc0000000 #define FEATURE_1_BTI 1 #define FEATURE_1_PAC 2 /* Supported features based on the code generation options. */ #if defined(__ARM_FEATURE_BTI_DEFAULT) # define BTI_FLAG FEATURE_1_BTI #else # define BTI_FLAG 0 #endif #if __ARM_FEATURE_PAC_DEFAULT & 3 # define PAC_FLAG FEATURE_1_PAC #else # define PAC_FLAG 0 #endif /* Add a NT_GNU_PROPERTY_TYPE_0 note. */ #define GNU_PROPERTY(type, value) \ .section .note.gnu.property, "a"; \ .p2align 3; \ .word 4; \ .word 16; \ .word 5; \ .asciz "GNU"; \ .word type; \ .word 4; \ .word value; \ .word 0; #if defined(__linux__) || defined(__FreeBSD__) .section .note.GNU-stack, "", %progbits /* Add GNU property note if built with branch protection. */ # if (BTI_FLAG|PAC_FLAG) != 0 GNU_PROPERTY (FEATURE_1_AND, BTI_FLAG|PAC_FLAG) # endif #endif