/* Unit tests of aarch64.c Copyright © 2022-2024 Samuel Lidén Borell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "../aarch64.c" #include "unittest.h" #include "codegen_testcommon.h" #include "alltests.h" static struct Csbe *create_csbe_a64(void) { enum CsbeErr e; struct CsbeConfig *cfg = tnewcfg(CSBEMT_EXEC); e = csbe_config_add_arch(cfg, CSBEC_AARCH64, CSBEEN_LITTLE_ENDIAN, CSBEOS_LINUX_GLIBC, CSBEOF_ELF_OBJ); tassert(e == CSBEE_OK); return tnewcsbe(cfg); } static void test_aarch64_iemit(void) { IEMIT_TEST_START IEMIT_CHK(STR_PRE_X(LR, SP, -32), "\xFE\x0F\x1E\xF8"); IEMIT_CHK(LDR_POST_X(LR, SP, 32), "\xFE\x07\x42\xF8"); IEMIT_CHK(STR_X(LR, SP), "\xFE\x03\x00\xF9"); IEMIT_CHK(LDR_X(LR, SP), "\xFE\x03\x40\xF9"); IEMIT_CHK(SUB_IMM_X(SP, SP, 16), "\xFF\x43\x00\xD1"); IEMIT_CHK(SUB_IMM_X(SP, SP, 0x220), "\xFF\x83\x08\xD1"); IEMIT_CHK(ADD_IMM_X(SP, SP, 0x220), "\xFF\x83\x08\x91"); IEMIT_CHK(CBZ(15, (uint32)-8L, 1), "\xCF\xFF\xFF\xB4"); IEMIT_CHK(ADRP(R17, 0xE5824000>>12), "\x31\xC1\x72\x90"); IEMIT_CHK(ADRP(R17, 0xfffff), "\xF1\xFF\x7F\xF0"); IEMIT_CHK(RET(LR), "\xC0\x03\x5F\xD6"); IEMIT_TEST_END } static void test_aarch64_iemit_opcodes(void) { IEMIT_TEST_START IEMIT_CHK(IEMIT_IMM12(/*rd*/0, /*rn*/19, /*imm*/0x1, 0x00, 0x11), "\x60\x06\x00\x11"); /* add w0, w19, #0x1 */ IEMIT_CHK(IEMIT_IMM12(/*rd*/19, /*rn*/19, /*imm*/0x60, 0x01, 0x91), "\x73\x82\x01\x91"); /* add x19, x19, #0x60 */ IEMIT_CHK(IEMIT_IMM16(/*rd*/1, /*imm*/0x25, 0x80, 0x52), "\xA1\x04\x80\x52"); /* movz w */ IEMIT_CHK(IEMIT_RR(/*rd*/19, /*rn*/20, 0x00, /*rm*/19, 0x00, 0x8B), "\x93\x02\x13\x8B"); /* add x19, x20, x19 */ IEMIT_CHK(IEMIT_IMM26(/*imm*/0x3FFFEFD, /*opc*/0x14), "\xFD\xFE\xFF\x17"); /* b -259*4 */ IEMIT_CHK(IEMIT_IMM19(/*addr*/0x7FEFD, /*extra*/27, /*opc*/0xB4), "\xBB\xDF\xFF\xB4"); /* cbz x27, -259*4 */ IEMIT_TEST_END } static struct Csbe *start_func(int num_vars, int num_ebbs) { struct Csbe *csbe = create_csbe_a64(); assert(num_ebbs >= 1); CHK(csbe_set_num_funcdefs(csbe, 1)); CHK(csbe_funcdef_start(csbe, 0, 0, CSBEABI_C_NORMAL, CSBEFD_OBJGLOBAL)); csbe_funcdef_set_name(csbe, "test", 4); csbe_type_simple(csbe, CSBET_U32); csbe_funcdef_end(csbe); CHK(csbe_defs_done(csbe)); CHK(csbe_funcbody_start(csbe, 0, NULL, NULL, num_ebbs, num_vars)); return csbe; } static void add_simple_var(struct Csbe *csbe, enum CsbeTypeKind simpletype, unsigned var_id) { csbe_funcbody_vardef_start(csbe, CSBEVD_SIMPLE, var_id, CSBE_VARLANE_NONE); csbe_type_simple(csbe, simpletype); csbe_funcbody_vardef_end(csbe); } static void gen_code(struct CgCtx *cg, struct Csbe *csbe) { CHK(csbe_funcbody_end(csbe)); init_cg(cg, csbe); tassert(gather_func_info(cg, csbe->funcdefs[0].funcbody)); tassert(aarch64_codegen(cg, &csbe->funcdefs[0])); cg_lastchunk(cg); tassert(cg->code.chunks != NULL); } /** * Tests generation of a function that simply returns 0x1234. * * Since there are no stack allocations, and no outbound calls, * there is no need for a function prologue/epilogue. */ static void test_aarch64_func_trivial(void) { struct Csbe *csbe = start_func(/*var's*/0, /*ebb's*/1); struct CgCtx c, *cg = &c; CHK(csbe_ebb_start(csbe, 0, CSBEEF_DEFAULT)); CHK(csbe_op_start(csbe, CSBEO_RETURN_ARG)); csbe_operand_immed(csbe, CSBET_U32, 0x7ACF); csbe_op_end(csbe); tassert(init_cgctx(&c, csbe, NULL)); gen_code(&c, csbe); CODEGEN_CHK( "\xE0\x59\x8F\x52" /* mov w0, 0x1234 */ "\xC0\x03\x5F\xD6" /* ret */ ); } /** * Tests generation of a function that returns (11+22)-33. */ static void test_aarch64_func_expr(void) { enum LocalVars { VAR_A }; struct Csbe *csbe = start_func(/*var's*/1, /*ebb's*/1); struct CgCtx c, *cg = &c; CHK(csbe_ebb_start(csbe, 0, CSBEEF_DEFAULT)); add_simple_var(csbe, CSBET_U32, VAR_A); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* a <- 11 */ csbe_operand_immed(csbe, CSBET_U32, 11); csbe_operand_var_out(csbe, VAR_A, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_ADD)); /* a <- a + 22 */ csbe_operand_var_in(csbe, VAR_A, CSBE_OPV_DISCARD); csbe_operand_immed(csbe, CSBET_U32, 22); csbe_operand_var_out(csbe, VAR_A, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_SUB)); /* a <- a - 33 */ csbe_operand_var_in(csbe, VAR_A, CSBE_OPV_DISCARD); csbe_operand_immed(csbe, CSBET_U32, 33); csbe_operand_var_out(csbe, VAR_A, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_SUB)); /* a <- 76543 - a */ csbe_operand_immed(csbe, CSBET_U32, 76543); csbe_operand_var_in(csbe, VAR_A, CSBE_OPV_DISCARD); csbe_operand_var_out(csbe, VAR_A, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_RETURN_ARG)); csbe_operand_var_in(csbe, VAR_A, 0); csbe_op_end(csbe); tassert(init_cgctx(&c, csbe, NULL)); gen_code(&c, csbe); CODEGEN_CHK( "\x69\x01\x80\x52" /* mov w9, #0xb */ "\x29\x59\x00\x11" /* add w9, w9, #0x16 */ "\x29\x85\x00\x51" /* sub w9, w9, #0x21 */ "\xf0\x5f\x85\x52" /* mov w16, #0x2aff */ "\x30\x00\xa0\x72" /* movk w16, #0x1, lsl #16 */ "\x09\x02\x09\x4b" /* sub w9, w16, w9 */ "\xe0\x03\x09\x2a" /* mov w0, w9 */ "\xC0\x03\x5F\xD6" /* ret */ ); } /** * Tests generation of a function that returns arg2*((11*arg1)+arg2-22)-arg2 */ static void test_aarch64_func_arg(void) { enum LocalVars { ARG1, ARG2, VAR_A, VAR_B, VAR_C, VAR_D, VAR_RV, NUM_PARAMS = ARG2+1, NUM_VARS = VAR_RV+1 }; struct Csbe *csbe = create_csbe_a64(); struct CgCtx c, *cg = &c; /* Define function */ CHK(csbe_set_num_funcdefs(csbe, 1)); CHK(csbe_funcdef_start(csbe, 0, NUM_PARAMS, CSBEABI_C_NORMAL, CSBEFD_OBJGLOBAL)); csbe_funcdef_set_name(csbe, "test", 4); csbe_type_simple(csbe, CSBET_U32); /* return type */ csbe_type_simple(csbe, CSBET_U32); /* arg1 */ csbe_type_simple(csbe, CSBET_U32); /* arg2 */ csbe_funcdef_end(csbe); CHK(csbe_defs_done(csbe)); CHK(csbe_funcbody_start(csbe, 0, NULL, NULL, 1, NUM_VARS)); csbe_funcbody_paramdef(csbe, CSBEVD_MULTI_READ, ARG1); csbe_funcbody_paramdef(csbe, CSBEVD_MULTI_READ, ARG2); /* Add IR code. a <- 11 * arg1 b <- a + arg2 c <- b - 22 d <- arg2 * c rv <- d - arg2 */ CHK(csbe_ebb_start(csbe, 0, CSBEEF_DEFAULT)); add_simple_var(csbe, CSBET_U32, VAR_A); add_simple_var(csbe, CSBET_U32, VAR_B); add_simple_var(csbe, CSBET_U32, VAR_C); add_simple_var(csbe, CSBET_U32, VAR_D); add_simple_var(csbe, CSBET_U32, VAR_RV); CHK(csbe_op_start(csbe, CSBEO_MUL)); /* a <- 11 * arg1 */ csbe_operand_immed(csbe, CSBET_U32, 11); csbe_operand_var_in(csbe, ARG1, 0); csbe_operand_var_out(csbe, VAR_A, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_ADD)); /* b <- a + arg2 */ csbe_operand_var_in(csbe, VAR_A, CSBE_OPV_DISCARD); csbe_operand_var_in(csbe, ARG2, 0); csbe_operand_var_out(csbe, VAR_B, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_SUB)); /* c <- b - 22 */ csbe_operand_var_in(csbe, VAR_B, CSBE_OPV_DISCARD); csbe_operand_immed(csbe, CSBET_U32, 22); csbe_operand_var_out(csbe, VAR_C, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_MUL)); /* d <- arg2 * c */ csbe_operand_var_in(csbe, ARG2, 0); csbe_operand_var_in(csbe, VAR_C, CSBE_OPV_DISCARD); csbe_operand_var_out(csbe, VAR_D, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_SUB)); /* rv <- d - arg2 */ csbe_operand_var_in(csbe, VAR_D, CSBE_OPV_DISCARD); csbe_operand_var_in(csbe, ARG2, 0); csbe_operand_var_out(csbe, VAR_RV, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_RETURN_ARG)); csbe_operand_var_in(csbe, VAR_RV, 0); csbe_op_end(csbe); tassert(init_cgctx(&c, csbe, NULL)); gen_code(&c, csbe); CODEGEN_CHK( "\x70\x01\x80\x52" /* mov w16, #0xb */ "\x09\x7e\x00\x1b" /* mul w9, w16, w0 */ "\x2a\x01\x01\x0b" /* add w10, w9, w1 */ "\x4b\x59\x00\x51" /* sub w11, w10, #0x16 */ "\x2c\x7c\x0b\x1b" /* mul w12, w1, w11 */ "\x8d\x01\x01\x4b" /* sub w13, w12, w1 */ /* TODO should look ahead and write result directly to w0 */ "\xe0\x03\x0d\x2a" /* mov w0, w13 */ "\xc0\x03\x5f\xd6" /* ret */ ); } /** * Tests generation of a function with an endless loop * (this tests unconditional backward jumps) */ static void test_aarch64_func_jump_backward(void) { enum LocalVars { VAR_I }; struct Csbe *csbe = start_func(/*var's*/1, /*ebb's*/2); struct CgCtx c, *cg = &c; CHK(csbe_ebb_start(csbe, 0, CSBEEF_DEFAULT)); add_simple_var(csbe, CSBET_U32, VAR_I); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* i <- 0 */ csbe_operand_immed(csbe, CSBET_U32, 0); csbe_operand_var_out(csbe, VAR_I, 0); csbe_op_end(csbe); CHK(csbe_ebb_start(csbe, 1, CSBEEF_DEFAULT)); CHK(csbe_op_start(csbe, CSBEO_ADD)); /* loop: a <- a + 1 */ csbe_operand_var_in(csbe, VAR_I, CSBE_OPV_DISCARD); csbe_operand_immed(csbe, CSBET_U32, 1); csbe_operand_var_out(csbe, VAR_I, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_JUMP)); /* goto loop */ csbe_operand_ebb(csbe, 1); csbe_op_end(csbe); tassert(init_cgctx(&c, csbe, NULL)); gen_code(&c, csbe); CODEGEN_CHK( "\x09\x00\x80\x52" /* mov w9, #0x0 */ "\x29\x05\x00\x11" /* add w9, w9, #0x1 */ "\xFF\xFF\xFF\x17" /* b -1 */ "\xC0\x03\x5F\xD6" /* ret */ ); } /** * Tests generation of a function with a forward jump */ static void test_aarch64_func_jump_forward(void) { enum LocalVars { VAR_I }; struct Csbe *csbe = start_func(/*var's*/1, /*ebb's*/3); struct CgCtx c, *cg = &c; CHK(csbe_ebb_start(csbe, 0, CSBEEF_DEFAULT)); add_simple_var(csbe, CSBET_U32, VAR_I); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* i <- 1 */ csbe_operand_immed(csbe, CSBET_U32, 1); csbe_operand_var_out(csbe, VAR_I, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_JUMP)); /* goto skip */ csbe_operand_ebb(csbe, 2); csbe_op_end(csbe); CHK(csbe_ebb_start(csbe, 1, CSBEEF_DEFAULT)); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* i <- 2 */ csbe_operand_immed(csbe, CSBET_U32, 2); csbe_operand_var_out(csbe, VAR_I, 0); csbe_op_end(csbe); CHK(csbe_ebb_start(csbe, 2, CSBEEF_DEFAULT)); CHK(csbe_op_start(csbe, CSBEO_ADD)); /* skip: i <- i + 1 */ csbe_operand_var_in(csbe, VAR_I, CSBE_OPV_DISCARD); csbe_operand_immed(csbe, CSBET_U32, 0x10); csbe_operand_var_out(csbe, VAR_I, 0); csbe_op_end(csbe); tassert(init_cgctx(&c, csbe, NULL)); gen_code(&c, csbe); CODEGEN_CHK( "\x29\x00\x80\x52" /* mov w9, #0x1 */ "\x02\x00\x00\x14" /* b +1 */ "\x49\x00\x80\x52" /* mov w9, #0x2 */ "\x29\x41\x00\x11" /* add w9, w9, #0x10 */ "\xC0\x03\x5F\xD6" /* ret */ ); } /** * Tests generation of a function with a forward jump */ static void test_aarch64_func_condjump(void) { enum LocalVars { VAR_A, VAR_B }; struct Csbe *csbe = start_func(/*var's*/2, /*ebb's*/3); struct CgCtx c, *cg = &c; CHK(csbe_ebb_start(csbe, 0, CSBEEF_DEFAULT)); add_simple_var(csbe, CSBET_U32, VAR_A); add_simple_var(csbe, CSBET_U32, VAR_B); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* a <- 1 */ csbe_operand_immed(csbe, CSBET_U32, 1); csbe_operand_var_out(csbe, VAR_A, 0); csbe_op_end(csbe); CHK(csbe_ebb_start(csbe, 1, CSBEEF_DEFAULT)); CHK(csbe_op_start(csbe, CSBEO_CONDJUMP)); /* up: if a==0 goto down */ csbe_operand_ebb(csbe, 2); csbe_operand_var_in(csbe, VAR_A, 0); csbe_operand_enum(csbe, CSBEBT_Z); csbe_operand_enum(csbe, CSBEBB_UNKNOWN); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* b <- 22 */ csbe_operand_immed(csbe, CSBET_U32, 22); csbe_operand_var_out(csbe, VAR_B, 0); csbe_op_end(csbe); CHK(csbe_ebb_start(csbe, 2, CSBEEF_DEFAULT)); CHK(csbe_op_start(csbe, CSBEO_CONDJUMP)); /* down: if a!=0 goto up */ csbe_operand_ebb(csbe, 1); csbe_operand_var_in(csbe, VAR_A, 0); csbe_operand_enum(csbe, CSBEBT_NZ); csbe_operand_enum(csbe, CSBEBB_UNKNOWN); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* b <- 33 */ csbe_operand_immed(csbe, CSBET_U32, 33); csbe_operand_var_out(csbe, VAR_B, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_CONDJUMP)); /* if b>0 goto up */ csbe_operand_ebb(csbe, 1); csbe_operand_var_in(csbe, VAR_B, 0); csbe_operand_enum(csbe, CSBEBT_GZ); csbe_operand_enum(csbe, CSBEBB_UNKNOWN); csbe_op_end(csbe); tassert(init_cgctx(&c, csbe, NULL)); gen_code(&c, csbe); CODEGEN_CHK( "\x29\x00\x80\x52" /* mov w9, #0x1 */ "\x49\x00\x00\x34" /* cbz w9, c */ "\xCA\x02\x80\x52" /* mov w10, #0x16 */ "\xC9\xFF\xFF\x35" /* cbnz w9, 4 */ "\x2A\x04\x80\x52" /* mov w10, #0x21 */ "\x5F\x01\x00\x71" /* cmp w10, #0x0 */ "\x6C\xFF\xFF\x54" /* b.gt 4 */ "\xC0\x03\x5F\xD6" /* ret */ ); } /** * Tests generation of a call to a function, in a case where * callee-saved registers need to be used. */ static void test_aarch64_func_call_saverestore(void) { enum LocalVars { VAR_A, VAR_B }; struct Csbe *csbe = start_func(/*var's*/2, /*ebb's*/1); struct CgCtx c, *cg = &c; CHK(csbe_ebb_start(csbe, 0, CSBEEF_DEFAULT)); add_simple_var(csbe, CSBET_U32, VAR_A); add_simple_var(csbe, CSBET_I8, VAR_B); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* a <- 11 */ csbe_operand_immed(csbe, CSBET_U32, 11); csbe_operand_var_out(csbe, VAR_A, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* b <- -3 */ csbe_operand_immed(csbe, CSBET_I8, -3); csbe_operand_var_out(csbe, VAR_B, 0); csbe_op_end(csbe); /* Call a function. This will clobber the registers used by A and B */ CHK(csbe_call_start(csbe, /*num_args=*/0)); CHK(csbe_op_start(csbe, CSBEO_CALL_FUNCDEF)); csbe_operand_callinfo(csbe); csbe_operand_enum(csbe, CSBECM_NORMAL); csbe_operand_funcdef(csbe, /*func_id=*/0); /* call self */ csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_CALL_DISCARD_RETURN)); csbe_op_end(csbe); /* Use VAR_A that was allocated to a clobbered register */ CHK(csbe_op_start(csbe, CSBEO_RETURN_ARG)); csbe_operand_var_in(csbe, VAR_A, 0); csbe_op_end(csbe); tassert(init_cgctx(&c, csbe, NULL)); gen_code(&c, csbe); CODEGEN_CHK( "\xfe\x0f\x1e\xf8" /* str x30, [sp, #-32]! */ "\xf2\x0f\x00\xf9" /* str x18, [sp, #24] */ "\xf3\x0b\x00\xf9" /* str x19, [sp, #16] */ "\x72\x01\x80\x52" /* mov x18, #11 */ "\x53\x00\x80\x12" /* mov w19, #-3 */ "\x00\x00\x00\x94" /* bl 0 (relocations not processed) */ "\xe0\x03\x12\x2a" /* mov w0, w18 */ "\xf2\x0f\x40\xf9" /* ldr x18, [sp, #24] */ "\xf3\x0b\x40\xf9" /* ldr x19, [sp, #16] */ "\xfe\x07\x42\xf8" /* ldr x30, [sp], #32 */ "\xc0\x03\x5f\xd6" /* ret */ ); } /** * Tests generation of signed & large immediates. */ static void test_aarch64_immed(void) { enum LocalVars { VAR_I, VAR_L }; struct Csbe *csbe = start_func(/*var's*/2, /*ebb's*/1); struct CgCtx c, *cg = &c; uint64 imm64; CHK(csbe_ebb_start(csbe, 0, CSBEEF_DEFAULT)); add_simple_var(csbe, CSBET_U32, VAR_I); add_simple_var(csbe, CSBET_U64, VAR_L); /* 16-bit unsigned immed */ CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* i <- 65535 */ csbe_operand_immed(csbe, CSBET_U32, 65535L); csbe_operand_var_out(csbe, VAR_I, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* l <- 65535 */ csbe_operand_immed(csbe, CSBET_U64, 65535L); csbe_operand_var_out(csbe, VAR_L, 0); csbe_op_end(csbe); /* 16-bit signed immed */ CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* i <- -65536 */ csbe_operand_immed(csbe, CSBET_U32, -65536L); csbe_operand_var_out(csbe, VAR_I, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* l <- -65536 */ csbe_operand_immed(csbe, CSBET_U64, -65536L); csbe_operand_var_out(csbe, VAR_L, 0); csbe_op_end(csbe); /* 32-bit immed */ CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* i <- -1412623820 */ csbe_operand_immed(csbe, CSBET_U32, -1412623820); csbe_operand_var_out(csbe, VAR_I, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* l <- 0x40000000 */ csbe_operand_immed(csbe, CSBET_U64, 0x40000000); csbe_operand_var_out(csbe, VAR_L, 0); csbe_op_end(csbe); /* 64-bit immed */ CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* l <- -4294967295 */ imm64 = 0xffffffff; imm64 <<= 32; imm64 |= 0x00000001; csbe_operand_immed(csbe, CSBET_U64, imm64); csbe_operand_var_out(csbe, VAR_L, 0); csbe_op_end(csbe); CHK(csbe_op_start(csbe, CSBEO_MOVE)); /* l <- 4294967295 */ imm64 = 0xabcdef01; imm64 <<= 32; imm64 |= 0x23456789; csbe_operand_immed(csbe, CSBET_U64, imm64); csbe_operand_var_out(csbe, VAR_L, 0); csbe_op_end(csbe); tassert(init_cgctx(&c, csbe, NULL)); gen_code(&c, csbe); CODEGEN_CHK( "\xe9\xff\x9f\x52" /* mov w9, #0xffff */ "\xea\xff\x9f\xd2" /* mov x10, #0xffff */ "\xe9\xff\xbf\x52" /* mov w9, #0xffff0000 */ "\xea\xff\x9f\x92" /* mov x10, #0xffffffffffff0000 */ "\x89\x46\x82\x52" /* mov w9, #0x1234 */ "\xa9\x79\xb5\x72" /* movk w9, #0xabcd, lsl #16 */ "\x0a\x00\xa8\xd2" /* mov x10, #0x40000000 */ "\x2a\x00\x80\xd2" /* mov x10, #0x1 */ "\x0a\x00\xa0\xf2" /* movk x10, #0x0, lsl #16 */ "\xea\xff\xdf\xf2" /* movk x10, #0xffff, lsl #32 */ "\xea\xff\xff\xf2" /* movk x10, #0xffff, lsl #48 */ "\x2a\xf1\x8c\xd2" /* mov x10, #0x6789 */ "\xaa\x68\xa4\xf2" /* movk x10, #0x2345, lsl #16 */ "\x2a\xe0\xdd\xf2" /* movk x10, #0xef01, lsl #32 */ "\xaa\x79\xf5\xf2" /* movk x10, #0xabcd, lsl #48 */ "\xc0\x03\x5f\xd6" /* ret */ ); } const TestFunctionInfo tests_aarch64[] = { TEST_INFO(test_aarch64_iemit) TEST_INFO(test_aarch64_iemit_opcodes) TEST_INFO(test_aarch64_func_trivial) TEST_INFO(test_aarch64_func_expr) TEST_INFO(test_aarch64_func_arg) TEST_INFO(test_aarch64_func_jump_backward) TEST_INFO(test_aarch64_func_jump_forward) TEST_INFO(test_aarch64_func_condjump) TEST_INFO(test_aarch64_func_call_saverestore) TEST_INFO(test_aarch64_immed) TEST_END };