diff --git a/API_CHANGES b/API_CHANGES index 20fc6451a..0fc7b09c4 100644 --- a/API_CHANGES +++ b/API_CHANGES @@ -1,5 +1,10 @@ This file is the short summary of the API changes: +10.06.2023 - Backward compatible + Emulation for atomic operations in narrow bitwidths is + configurable at build time, SLJIT_HAS_ATOMIC_{8,16}BIT + provide availability at runtime. + 16.02.2022 - Non-backward compatible The sljit_emit_cmov operation is replaced by sljit_emit_select. diff --git a/sljit_src/sljitConfig.h b/sljit_src/sljitConfig.h index ae0558c3c..fcbd6419f 100644 --- a/sljit_src/sljitConfig.h +++ b/sljit_src/sljitConfig.h @@ -148,6 +148,11 @@ extern "C" { #define SLJIT_VERBOSE 1 #endif +/* Atomic emulation level */ +#ifndef SLJIT_ATOMIC_EMULATION +#define SLJIT_ATOMIC_EMULATION 0 +#endif + /* SLJIT_IS_FPU_AVAILABLE The availability of the FPU can be controlled by SLJIT_IS_FPU_AVAILABLE. diff --git a/sljit_src/sljitConfigInternal.h b/sljit_src/sljitConfigInternal.h index 1769f42a8..edbf3f668 100644 --- a/sljit_src/sljitConfigInternal.h +++ b/sljit_src/sljitConfigInternal.h @@ -779,13 +779,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #elif (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH) -#define SLJIT_NUMBER_OF_REGISTERS 23 +#define SLJIT_NUMBER_OF_REGISTERS 22 #define SLJIT_NUMBER_OF_SAVED_REGISTERS 10 #define SLJIT_LOCALS_OFFSET_BASE 0 #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 12 #define SLJIT_MASKED_SHIFT 1 #define SLJIT_MASKED_SHIFT32 1 +#define SLJIT_ATOMIC_WIDTH 32 #elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) diff --git a/sljit_src/sljitLir.h b/sljit_src/sljitLir.h index c7a1c1941..e671c7328 100644 --- a/sljit_src/sljitLir.h +++ b/sljit_src/sljitLir.h @@ -658,6 +658,10 @@ static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler #define SLJIT_HAS_COPY_F32 9 /* [Emulated] Copy from/to f64 operation is available (see sljit_emit_fcopy). */ #define SLJIT_HAS_COPY_F64 10 +/* [Emulated] Loading/Storing 8bit atomics is available. */ +#define SLJIT_HAS_ATOMIC_8BIT 11 +/* [Emulated] Loading/Storing 16bit atomics is available. */ +#define SLJIT_HAS_ATOMIC_16BIT 12 #if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) /* [Not emulated] SSE2 support is available on x86. */ @@ -1804,7 +1808,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler - the memory operation (op) and the base address (stored in mem_reg) passed to the load/store operations must be the same (the mem_reg can be a different register, only its value must be the same) - - an store must always follow a load for the same transaction. + - an store must always follow a load for the same transaction, but + loads might be abandoned + - if the CPU defines a minimum bit width supported (SLJIT_ATOMIC_WIDTH) + then the memory address must be aligned to it; alternatively smaller + atomic types can be supported by enabling SLJIT_ATOMIC_EMULATION op must be between SLJIT_MOV and SLJIT_MOV_P, excluding all signed loads such as SLJIT_MOV32_S16 diff --git a/sljit_src/sljitNativeLOONGARCH_64.c b/sljit_src/sljitNativeLOONGARCH_64.c index eea8a3286..15b936fa4 100644 --- a/sljit_src/sljitNativeLOONGARCH_64.c +++ b/sljit_src/sljitNativeLOONGARCH_64.c @@ -36,19 +36,20 @@ typedef sljit_u32 sljit_ins; #define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) #define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) #define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4) +#define TMP_REG4 (SLJIT_NUMBER_OF_REGISTERS + 5) #define TMP_ZERO 0 /* Flags are kept in volatile registers. */ -#define EQUAL_FLAG (SLJIT_NUMBER_OF_REGISTERS + 5) +#define EQUAL_FLAG (SLJIT_NUMBER_OF_REGISTERS + 6) #define RETURN_ADDR_REG TMP_REG2 -#define OTHER_FLAG (SLJIT_NUMBER_OF_REGISTERS + 6) +#define OTHER_FLAG (SLJIT_NUMBER_OF_REGISTERS + 7) #define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) #define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = { - 0, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 22, 31, 30, 29, 28, 27, 26, 25, 24, 23, 3, 13, 1, 14, 12, 15 +static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 8] = { + 0, 4, 5, 6, 7, 8, 9, 10, 11, 17, 18, 19, 20, 22, 31, 30, 29, 28, 27, 26, 25, 24, 23, 3, 13, 1, 14, 16, 12, 15 }; static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = { @@ -62,7 +63,7 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = { /* LoongArch instructions are 32 bits wide, belonging to 9 basic instruction formats (and variants of them): -| Format name | Composition | +| Format name | Composition | | 2R | Opcode + Rj + Rd | | 3R | Opcode + Rk + Rj + Rd | | 4R | Opcode + Ra + Rk + Rj + Rd | @@ -642,6 +643,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) case SLJIT_HAS_COPY_F64: return 1; + case SLJIT_HAS_ATOMIC_8BIT: + case SLJIT_HAS_ATOMIC_16BIT: + return SLJIT_ATOMIC_EMULATION; + default: return 0; } @@ -2449,8 +2454,10 @@ static sljit_ins get_jump_instruction(sljit_s32 type) { switch (type) { case SLJIT_EQUAL: + case SLJIT_ATOMIC_NOT_STORED: return BNE | RJ(EQUAL_FLAG) | RD(TMP_ZERO); case SLJIT_NOT_EQUAL: + case SLJIT_ATOMIC_STORED: return BEQ | RJ(EQUAL_FLAG) | RD(TMP_ZERO); case SLJIT_LESS: case SLJIT_GREATER: @@ -2734,6 +2741,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co FAIL_IF(push_inst(compiler, SLTUI | RD(dst_r) | RJ(EQUAL_FLAG) | IMM_I12(1))); src_r = dst_r; break; + case SLJIT_ATOMIC_STORED: + case SLJIT_ATOMIC_NOT_STORED: + FAIL_IF(push_inst(compiler, SLTUI | RD(dst_r) | RJ(EQUAL_FLAG) | IMM_I12(1))); + src_r = dst_r; + invert ^= 0x1; + break; case SLJIT_OVERFLOW: case SLJIT_NOT_OVERFLOW: if (compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)) { @@ -2933,15 +2946,56 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler sljit_s32 dst_reg, sljit_s32 mem_reg) { - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(dst_reg); - SLJIT_UNUSED_ARG(mem_reg); + sljit_ins ins = LL_W; + sljit_s32 dst = TMP_REG2; + sljit_s32 mem = mem_reg; CHECK_ERROR(); CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg)); - return SLJIT_ERR_UNSUPPORTED; + op = GET_OPCODE(op); + switch (op) { +#if SLJIT_ATOMIC_EMULATION + case SLJIT_MOV_U8: + case SLJIT_MOV_U16: + mem = TMP_REG1; + FAIL_IF(push_inst(compiler, ANDI | RD(TMP_REG3) | RJ(mem_reg) | IMM_I12(0x3))); + FAIL_IF(push_inst(compiler, XOR | RD(mem) | RJ(TMP_REG3) | RK(mem_reg))); + break; +#endif /* SLJIT_ATOMIC_EMULATION */ + case SLJIT_MOV_P: + case SLJIT_MOV: + ins = LL_D; + dst = dst_reg; + break; + } + + FAIL_IF(push_inst(compiler, ins | RD(dst) | RJ(mem))); + +#if SLJIT_ATOMIC_EMULATION + if (mem != mem_reg) + FAIL_IF(push_inst(compiler, SLLI_W | RD(TMP_REG3) | RJ(TMP_REG3) | IMM_I12(0x3))); +#endif /* SLJIT_ATOMIC_EMULATION */ + + switch (op) { + case SLJIT_MOV_U8: +#if SLJIT_ATOMIC_EMULATION + FAIL_IF(push_inst(compiler, SRL_W | RD(dst) | RJ(dst) | RK(TMP_REG3))); +#endif /* SLJIT_ATOMIC_EMULATION */ + FAIL_IF(push_inst(compiler, ANDI | RD(dst_reg) | RJ(dst) | IMM_I12(0xff))); + break; + case SLJIT_MOV_U16: +#if SLJIT_ATOMIC_EMULATION + FAIL_IF(push_inst(compiler, BEQZ | RJ(TMP_REG3) | IMM_I21(1 + 2))); + FAIL_IF(push_inst(compiler, SRL_W | RD(dst_reg) | RJ(dst) | RK(TMP_REG3))); + FAIL_IF(push_inst(compiler, B | IMM_I26(1 + 1))); +#endif /* SLJIT_ATOMIC_EMULATION */ + return push_inst(compiler, BSTRPICK_W | RD(dst_reg) | RJ(dst) | (15 << 16)); + case SLJIT_MOV_U32: + case SLJIT_MOV32: + return push_inst(compiler, BSTRPICK_D | RD(dst_reg) | RJ(dst) | (31 << 16)); + } + return SLJIT_SUCCESS; } SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler, @@ -2950,16 +3004,63 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler sljit_s32 mem_reg, sljit_s32 temp_reg) { - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(src_reg); - SLJIT_UNUSED_ARG(mem_reg); - SLJIT_UNUSED_ARG(temp_reg); + sljit_ins ins = SC_W; + sljit_ins chk = ORI | RD(EQUAL_FLAG) | RJ(temp_reg) | RK(TMP_ZERO); + sljit_s32 mem = mem_reg; CHECK_ERROR(); CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg)); - return SLJIT_ERR_UNSUPPORTED; + op = GET_OPCODE(op); + +#if SLJIT_ATOMIC_EMULATION + switch (op) { + case SLJIT_MOV_U8: + case SLJIT_MOV_U16: + mem = TMP_REG1; + FAIL_IF(push_inst(compiler, ANDI | RD(TMP_REG3) | RJ(mem_reg) | IMM_I12(0x3))); + FAIL_IF(push_inst(compiler, XOR | RD(mem) | RJ(TMP_REG3) | RK(mem_reg))); + } +#endif /* SLJIY_ATOMIC_EMULATION */ + + switch (op) { + case SLJIT_MOV_U8: +#if SLJIT_ATOMIC_EMULATION + FAIL_IF(push_inst(compiler, SLLI_W | RD(TMP_REG3) | RJ(TMP_REG3) | IMM_I12(3))); + FAIL_IF(push_inst(compiler, LD_WU | RD(temp_reg) | RJ(mem))); + FAIL_IF(push_inst(compiler, ADDI_W | RD(TMP_REG2) | RJ(TMP_ZERO) | IMM_I12(0xff))); + FAIL_IF(push_inst(compiler, SLL_W | RD(TMP_REG2) | RJ(TMP_REG2) | RK(TMP_REG3))); + FAIL_IF(push_inst(compiler, ANDN | RD(temp_reg) | RJ(temp_reg) | RK(TMP_REG2))); + FAIL_IF(push_inst(compiler, ANDI | RD(TMP_REG4) | RJ(src_reg) | IMM_I12(0xff))); + FAIL_IF(push_inst(compiler, SLL_W | RD(TMP_REG4) | RJ(src_reg) | RK(TMP_REG3))); + FAIL_IF(push_inst(compiler, OR | RD(temp_reg) | RJ(temp_reg) | RK(TMP_REG4))); +#else + FAIL_IF(push_inst(compiler, ANDI | RD(temp_reg) | RJ(src_reg) | IMM_I12(0xff))); +#endif /* SLJIT_ATOMIC_EMULATION */ + break; + case SLJIT_MOV_U16: +#if SLJIT_ATOMIC_EMULATION + FAIL_IF(push_inst(compiler, LD_WU | RD(temp_reg) | RJ(mem))); + FAIL_IF(push_inst(compiler, BNEZ | RJ(TMP_REG3) | IMM_I21(1 + 2))); +#endif /* SLJIT_ATOMIC_EMULATION */ + FAIL_IF(push_inst(compiler, BSTRINS_W | RD(temp_reg) | RJ(src_reg) | (15 << 16))); +#if SLJIT_ATOMIC_EMULATION + FAIL_IF(push_inst(compiler, B | IMM_I26(1 + 1))); + FAIL_IF(push_inst(compiler, BSTRINS_W | RD(temp_reg) | RJ(src_reg) | (31 << 16) | (16 << 10))); +#endif /* SLJIT_ATOMIC_EMULATION */ + break; + case SLJIT_MOV_P: + case SLJIT_MOV: + ins = SC_D; + /* FALLTHRU */ + default: + FAIL_IF(push_inst(compiler, ORI | RD(temp_reg) | RJ(src_reg) | RK(TMP_ZERO))); + break; + } + + FAIL_IF(push_inst(compiler, ins | RD(temp_reg) | RJ(mem))); + + return chk ? push_inst(compiler, chk) : SLJIT_SUCCESS; } static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins) diff --git a/test_src/sljitTest.c b/test_src/sljitTest.c index e90ba6751..167653ccf 100644 --- a/test_src/sljitTest.c +++ b/test_src/sljitTest.c @@ -11537,22 +11537,35 @@ static void test92(void) { #if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \ || (defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM) \ - || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) + || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \ + || (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH) /* Test atomic load and store. */ executable_code code; struct sljit_compiler *compiler = sljit_create_compiler(NULL, NULL); struct sljit_label *label; struct sljit_jump *jump; - sljit_sw buf[38]; - sljit_s32 i; + sljit_sw buf[40]; + sljit_u8 padbyte; + sljit_sw padding = 0; + int i; if (verbose) printf("Run test92\n"); FAILED(!compiler, "cannot create compiler\n"); + if (sljit_has_cpu_feature(SLJIT_HAS_ATOMIC_8BIT)) { + padbyte = 0x55; + for (i = 0; i < (int)sizeof(sljit_sw); i++) { + padding |= padbyte; + padding <<= 8; + } + padding |= padbyte; + } else + padbyte = 0; + for (i = 0; i < 36; i++) - buf[i] = WCONST(0x5555555555555555, 0x55555555); + buf[i] = padding; buf[0] = 4678; *(sljit_u8*)(buf + 2) = 78; @@ -11569,6 +11582,7 @@ static void test92(void) ((sljit_s32*)(buf + 33))[1] = -1; #endif /* SLJIT_64BIT_ARCHITECTURE */ buf[37] = WCONST(0x1122334444332211, 0x11222211); + buf[38] = SLJIT_FUNC_ADDR(test92); sljit_emit_enter(compiler, 0, SLJIT_ARGS1(VOID, P), 5, 5, 0, 0, 2 * sizeof(sljit_sw)); @@ -11674,6 +11688,19 @@ static void test92(void) /* buf[19] */ sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 19 * sizeof(sljit_sw), SLJIT_R0, 0); + /* case: SLJIT_MOV_P */ + sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R2, 0, SLJIT_S0, 0, SLJIT_IMM, 38 * sizeof(sljit_sw)); + label = sljit_emit_label(compiler); + sljit_emit_atomic_load(compiler, SLJIT_MOV_P, SLJIT_R0, SLJIT_R2); + sljit_emit_op1(compiler, SLJIT_MOV_P, SLJIT_S1, 0, SLJIT_R0, 0); + sljit_emit_op1(compiler, SLJIT_MOV_P, SLJIT_R1, 0, SLJIT_R0, 0); + sljit_emit_op1(compiler, SLJIT_MOV_P, SLJIT_R0, 0, SLJIT_R2, 0); + /* buf[38] */ + sljit_emit_atomic_store(compiler, SLJIT_MOV_P | SLJIT_SET_ATOMIC_STORED, SLJIT_R0, SLJIT_R2, SLJIT_R1); + sljit_set_label(sljit_emit_jump(compiler, SLJIT_ATOMIC_NOT_STORED), label); + /* buf[39] */ + sljit_emit_op1(compiler, SLJIT_MOV_P, SLJIT_MEM1(SLJIT_S0), 39 * sizeof(sljit_sw), SLJIT_S1, 0); + sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R1, 0, SLJIT_S0, 0, SLJIT_IMM, 20 * sizeof(sljit_sw)); label = sljit_emit_label(compiler); sljit_emit_atomic_load(compiler, SLJIT_MOV_U8, SLJIT_R3, SLJIT_R1); @@ -11704,43 +11731,51 @@ static void test92(void) /* buf[25] */ sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 25 * sizeof(sljit_sw), SLJIT_R0, 0); - sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R1, 0, SLJIT_S0, 0, SLJIT_IMM, 26 * sizeof(sljit_sw) + 1); - label = sljit_emit_label(compiler); - sljit_emit_atomic_load(compiler, SLJIT_MOV_U8, SLJIT_R0, SLJIT_R1); - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_S2, 0, SLJIT_R0, 0); - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, 204); - /* buf[26] */ - sljit_emit_atomic_store(compiler, SLJIT_MOV_U8 | SLJIT_SET_ATOMIC_STORED, SLJIT_R2, SLJIT_R1, SLJIT_R0); - jump = sljit_emit_jump(compiler, SLJIT_ATOMIC_STORED); - sljit_set_label(sljit_emit_jump(compiler, SLJIT_JUMP), label); - sljit_set_label(jump, sljit_emit_label(compiler)); - /* buf[27] */ - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 27 * sizeof(sljit_sw), SLJIT_S2, 0); + if (sljit_has_cpu_feature(SLJIT_HAS_ATOMIC_8BIT)) { + /* case: byte aligned lower offset */ + sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R1, 0, SLJIT_S0, 0, SLJIT_IMM, 26 * sizeof(sljit_sw) + 1); + label = sljit_emit_label(compiler); + sljit_emit_atomic_load(compiler, SLJIT_MOV_U8, SLJIT_R0, SLJIT_R1); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_S2, 0, SLJIT_R0, 0); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, 204); + /* buf[26] */ + sljit_emit_atomic_store(compiler, SLJIT_MOV_U8 | SLJIT_SET_ATOMIC_STORED, SLJIT_R2, SLJIT_R1, SLJIT_R0); + jump = sljit_emit_jump(compiler, SLJIT_ATOMIC_STORED); + sljit_set_label(sljit_emit_jump(compiler, SLJIT_JUMP), label); + sljit_set_label(jump, sljit_emit_label(compiler)); + /* buf[27] */ + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 27 * sizeof(sljit_sw), SLJIT_S2, 0); + + /* case: byte aligned higher offset */ + sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R1, 0, SLJIT_S0, 0, SLJIT_IMM, 28 * sizeof(sljit_sw) + 2); + label = sljit_emit_label(compiler); + sljit_emit_atomic_load(compiler, SLJIT_MOV_U8, SLJIT_R0, SLJIT_R1); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_S1, 0, SLJIT_R0, 0); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, 240); + /* buf[28] */ + sljit_emit_atomic_store(compiler, SLJIT_MOV_U8 | SLJIT_SET_ATOMIC_STORED, SLJIT_R2, SLJIT_R1, SLJIT_R0); + sljit_set_label(sljit_emit_jump(compiler, SLJIT_ATOMIC_NOT_STORED), label); + /* buf[29] */ + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 29 * sizeof(sljit_sw), SLJIT_S1, 0); + sljit_emit_op_flags(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_ATOMIC_NOT_STORED); + } - sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R1, 0, SLJIT_S0, 0, SLJIT_IMM, 28 * sizeof(sljit_sw) + 2); - label = sljit_emit_label(compiler); - sljit_emit_atomic_load(compiler, SLJIT_MOV_U8, SLJIT_R0, SLJIT_R1); - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_S1, 0, SLJIT_R0, 0); - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, 240); - /* buf[28] */ - sljit_emit_atomic_store(compiler, SLJIT_MOV_U8 | SLJIT_SET_ATOMIC_STORED, SLJIT_R2, SLJIT_R1, SLJIT_R0); - sljit_set_label(sljit_emit_jump(compiler, SLJIT_ATOMIC_NOT_STORED), label); - /* buf[29] */ - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 29 * sizeof(sljit_sw), SLJIT_S1, 0); - sljit_emit_op_flags(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_ATOMIC_NOT_STORED); /* buf[30] */ sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 30 * sizeof(sljit_sw), SLJIT_R0, 0); - sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R1, 0, SLJIT_S0, 0, SLJIT_IMM, 31 * sizeof(sljit_sw) + 2); - label = sljit_emit_label(compiler); - sljit_emit_atomic_load(compiler, SLJIT_MOV_U16, SLJIT_R0, SLJIT_R1); - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_S1, 0, SLJIT_R0, 0); - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, 51403); - /* buf[31] */ - sljit_emit_atomic_store(compiler, SLJIT_MOV_U16 | SLJIT_SET_ATOMIC_STORED, SLJIT_R2, SLJIT_R1, SLJIT_R0); - sljit_set_label(sljit_emit_jump(compiler, SLJIT_ATOMIC_NOT_STORED), label); - /* buf[32] */ - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 32 * sizeof(sljit_sw), SLJIT_S1, 0); + if (sljit_has_cpu_feature(SLJIT_HAS_ATOMIC_16BIT)) { + /* case: half aligned lower offset */ + sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R1, 0, SLJIT_S0, 0, SLJIT_IMM, 31 * sizeof(sljit_sw) + 2); + label = sljit_emit_label(compiler); + sljit_emit_atomic_load(compiler, SLJIT_MOV_U16, SLJIT_R0, SLJIT_R1); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_S1, 0, SLJIT_R0, 0); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, 51403); + /* buf[31] */ + sljit_emit_atomic_store(compiler, SLJIT_MOV_U16 | SLJIT_SET_ATOMIC_STORED, SLJIT_R2, SLJIT_R1, SLJIT_R0); + sljit_set_label(sljit_emit_jump(compiler, SLJIT_ATOMIC_NOT_STORED), label); + /* buf[32] */ + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 32 * sizeof(sljit_sw), SLJIT_S1, 0); + } #if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R1, 0, SLJIT_S0, 0, SLJIT_IMM, 33 * sizeof(sljit_sw) + sizeof(sljit_u32)); @@ -11753,13 +11788,14 @@ static void test92(void) sljit_emit_atomic_store(compiler, SLJIT_MOV32 | SLJIT_SET_ATOMIC_STORED, SLJIT_R2, SLJIT_R1, SLJIT_R0); sljit_set_label(sljit_emit_jump(compiler, SLJIT_ATOMIC_NOT_STORED), label); /* buf[34] */ - sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 34 * sizeof(sljit_sw), SLJIT_S1, 0); + sljit_emit_op1(compiler, SLJIT_MOV32, SLJIT_MEM1(SLJIT_S0), 34 * sizeof(sljit_sw), SLJIT_S1, 0); #endif /* SLJIT_64BIT_ARCHITECTURE */ /* buf[35] */ sljit_emit_op_flags(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 35 * sizeof(sljit_sw), SLJIT_ATOMIC_STORED); - /* case50: abandoned atomic load is safe */ +#ifndef SLJIT_ATOMIC_WIDTH + /* case50: abandoned atomic load (byte) */ sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_IMM, 0); sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R1, 0, SLJIT_S0, 0, SLJIT_IMM, 37 * sizeof(sljit_sw)); sljit_emit_atomic_load(compiler, SLJIT_MOV_U8, SLJIT_R0, SLJIT_R1); @@ -11770,6 +11806,7 @@ static void test92(void) sljit_emit_atomic_store(compiler, SLJIT_MOV_U8, SLJIT_R2, SLJIT_R1, SLJIT_R0); /* buf[36] */ sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM1(SLJIT_S0), 36 * sizeof(sljit_sw), SLJIT_R2, 0); +#endif /* !SLJIT_ATOMIC_WIDTH */ sljit_emit_return_void(compiler); @@ -11782,63 +11819,73 @@ static void test92(void) FAILED(buf[0] != -9856, "test92 case 1 failed\n"); FAILED(buf[1] != 4678, "test92 case 2 failed\n"); FAILED(*(sljit_u8*)(buf + 2) != 203, "test92 case 3 failed\n"); - FAILED(((sljit_u8*)(buf + 2))[1] != 0x55, "test92 case 4 failed\n"); + FAILED(((sljit_u8*)(buf + 2))[1] != padbyte, "test92 case 4 failed\n"); FAILED(buf[3] != 78, "test92 case 5 failed\n"); FAILED(buf[4] != 203, "test92 case 6 failed\n"); FAILED(*(sljit_u8*)(buf + 5) != 97, "test92 case 7 failed\n"); - FAILED(((sljit_u8*)(buf + 5))[1] != 0x55, "test92 case 8 failed\n"); + FAILED(((sljit_u8*)(buf + 5))[1] != padbyte, "test92 case 8 failed\n"); FAILED(*(sljit_u32*)(buf + 6) != 211, "test92 case 9 failed\n"); FAILED(buf[7] != (sljit_sw)(buf + 5), "test92 case 10 failed\n"); FAILED(buf[8] != 97, "test92 case 11 failed\n"); FAILED(*(sljit_u16*)(buf + 9) != (sljit_u16)(sljit_sw)(buf + 9), "test92 case 12 failed\n"); - FAILED(((sljit_u8*)(buf + 9))[2] != 0x55, "test92 case 13 failed\n"); + FAILED(((sljit_u8*)(buf + 9))[2] != padbyte, "test92 case 13 failed\n"); FAILED(buf[10] != 17897, "test92 case 14 failed\n"); FAILED(buf[11] != (sljit_sw)(buf + 9), "test92 case 15 failed\n"); FAILED(*(sljit_u16*)(buf + 12) != 41306, "test92 case 16 failed\n"); - FAILED(((sljit_u8*)(buf + 12))[2] != 0x55, "test92 case 17 failed\n"); + FAILED(((sljit_u8*)(buf + 12))[2] != padbyte, "test92 case 17 failed\n"); FAILED(*(sljit_u32*)(buf + 13) != 57812, "test92 case 18 failed\n"); FAILED(buf[14] != 41306, "test92 case 19 failed\n"); FAILED(*(sljit_u32*)(buf + 15) != 987654321, "test92 case 20 failed\n"); #if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) - FAILED(((sljit_u8*)(buf + 15))[4] != 0x55, "test92 case 21 failed\n"); + FAILED(((sljit_u8*)(buf + 15))[4] != padbyte, "test92 case 21 failed\n"); #endif /* SLJIT_64BIT_ARCHITECTURE */ FAILED(buf[16] != 1234567890, "test92 case 22 failed\n"); FAILED(*(sljit_u32*)(buf + 17) != 678906789, "test92 case 23 failed\n"); #if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) - FAILED(((sljit_u8*)(buf + 17))[4] != 0x55, "test92 case 24 failed\n"); + FAILED(((sljit_u8*)(buf + 17))[4] != padbyte, "test92 case 24 failed\n"); #endif /* SLJIT_64BIT_ARCHITECTURE */ FAILED(*(sljit_u32*)(buf + 18) != 987609876, "test92 case 25 failed\n"); #if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) - FAILED(((sljit_u8*)(buf + 18))[4] != 0x55, "test92 case 25 (overflow) failed\n"); + FAILED(((sljit_u8*)(buf + 18))[4] != padbyte, "test92 case 25 (overflow) failed\n"); #endif /* SLJIT_64BIT_ARCHITECTURE */ FAILED(buf[19] != -573621, "test92 case 26 failed\n"); FAILED(*(sljit_u8*)(buf + 20) != 240, "test92 case 27 failed\n"); - FAILED(((sljit_u8*)(buf + 20))[1] != 0x55, "test92 case 28 failed\n"); + FAILED(((sljit_u8*)(buf + 20))[1] != padbyte, "test92 case 28 failed\n"); FAILED(buf[21] != 192, "test92 case 29 failed\n"); FAILED(buf[22] != -5893, "test92 case 30 failed\n"); FAILED(buf[23] != 4059, "test92 case 31 failed\n"); FAILED(buf[24] != 6359, "test92 case 32 failed\n"); FAILED(buf[25] != (sljit_sw)(buf + 23), "test92 case 33 failed\n"); - FAILED(((sljit_u8*)(buf + 26))[0] != 0x55, "test92 case 34 failed\n"); - FAILED(((sljit_u8*)(buf + 26))[1] != 204, "test92 case 35 failed\n"); - FAILED(((sljit_u8*)(buf + 26))[2] != 0x55, "test92 case 36 failed\n"); - FAILED(buf[27] != 105, "test92 case 37 failed\n"); - FAILED(((sljit_u8*)(buf + 28))[1] != 0x55, "test92 case 38 failed\n"); - FAILED(((sljit_u8*)(buf + 28))[2] != 240, "test92 case 39 failed\n"); - FAILED(((sljit_u8*)(buf + 28))[3] != 0x55, "test92 case 40 failed\n"); - FAILED(buf[29] != 13, "test92 case 41 failed\n"); - FAILED(buf[30] != 0, "test92 case 42 failed\n"); - FAILED(((sljit_u16*)(buf + 31))[0] != 0x5555, "test92 case 43 failed\n"); - FAILED(((sljit_u16*)(buf + 31))[1] != 51403, "test92 case 44 failed\n"); - FAILED(buf[32] != 14876, "test92 case 45 failed\n"); + if (sljit_has_cpu_feature(SLJIT_HAS_ATOMIC_8BIT)) { + FAILED(((sljit_u8*)(buf + 26))[0] != padbyte, "test92 case 34 failed\n"); + FAILED(((sljit_u8*)(buf + 26))[1] != 204, "test92 case 35 failed\n"); + FAILED(((sljit_u8*)(buf + 26))[2] != padbyte, "test92 case 36 failed\n"); + FAILED(buf[27] != 105, "test92 case 37 failed\n"); + FAILED(((sljit_u8*)(buf + 28))[1] != padbyte, "test92 case 38 failed\n"); + FAILED(((sljit_u8*)(buf + 28))[2] != 240, "test92 case 39 failed\n"); + FAILED(((sljit_u8*)(buf + 28))[3] != padbyte, "test92 case 40 failed\n"); + FAILED(buf[29] != 13, "test92 case 41 failed\n"); + FAILED(buf[30] != 0, "test92 case 42 failed\n"); + } + if (sljit_has_cpu_feature(SLJIT_HAS_ATOMIC_16BIT)) { + if (padbyte) + FAILED(((sljit_u16*)(buf + 31))[0] != 0x5555, "test92 case 43 failed\n"); + FAILED(((sljit_u16*)(buf + 31))[1] != 51403, "test92 case 44 failed\n"); + FAILED(buf[32] != 14876, "test92 case 45 failed\n"); + } #if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) - FAILED(((sljit_u32*)(buf + 33))[0] != 0x55555555, "test92 case 46 failed\n"); + if (padbyte) + FAILED(((sljit_u32*)(buf + 33))[0] != 0x55555555, "test92 case 46 failed\n"); FAILED(((sljit_u32*)(buf + 33))[1] != 0xdeadbeef, "test92 case 47 failed\n"); - FAILED(buf[34] != 0xffffffff, "test92 case 48 failed\n"); + FAILED(((sljit_u32*)(buf + 34))[0] != 0xffffffff, "test92 case 48 failed\n"); #endif /* SLJIT_64BIT_ARCHITECTURE */ FAILED(buf[35] != 1, "test92 case 49 failed\n"); +#ifndef SLJIT_ATOMIC_WIDTH FAILED(buf[36] != 0x11, "test92 case 50 (load) failed\n"); FAILED(((sljit_u8*)(buf + 37))[1] != buf[36], "test92 case 50 (store) failed\n"); +#endif /* !SLJIT_ATOMIC_WIDTH */ + FAILED(buf[38] != (sljit_sw)&buf[38], "test92 case 51 (store) failed \n"); + FAILED(buf[39] != SLJIT_FUNC_ADDR(test92), "test92 case 51 (load) failed \n"); sljit_free_code(code.code, NULL); #endif