mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-21 04:14:18 +08:00
arm64: support mnemonic win32 stack helpers
This commit is contained in:
parent
b1763f8629
commit
0decb1b86f
411
arm64-asm.c
411
arm64-asm.c
@ -58,9 +58,17 @@ typedef struct Operand {
|
||||
int8_t reg2;
|
||||
uint8_t reg_type;
|
||||
uint8_t shift;
|
||||
uint8_t addr_mode;
|
||||
int reg_tok;
|
||||
ExprValue e;
|
||||
} Operand;
|
||||
|
||||
enum {
|
||||
ADDR_OFF,
|
||||
ADDR_PRE,
|
||||
ADDR_POST,
|
||||
};
|
||||
|
||||
/* Forward declaration */
|
||||
static void parse_addr_operand(TCCState *s1, Operand *op);
|
||||
|
||||
@ -217,6 +225,8 @@ static void parse_operand(TCCState *s1, Operand *op)
|
||||
op->reg2 = -1;
|
||||
op->reg_type = 0;
|
||||
op->shift = 0;
|
||||
op->addr_mode = ADDR_OFF;
|
||||
op->reg_tok = 0;
|
||||
|
||||
/* Address operand in brackets [xn, ...] */
|
||||
if (tok == '[') {
|
||||
@ -230,6 +240,7 @@ static void parse_operand(TCCState *s1, Operand *op)
|
||||
op->type = OP_REG;
|
||||
op->reg = reg;
|
||||
op->reg_type = get_reg_type(tok);
|
||||
op->reg_tok = tok;
|
||||
next();
|
||||
return;
|
||||
}
|
||||
@ -244,7 +255,7 @@ static void parse_operand(TCCState *s1, Operand *op)
|
||||
}
|
||||
|
||||
/* Immediate or address expression */
|
||||
if (tok == '#' || tok == ':' || tok == '@') {
|
||||
if (tok == '#' || tok == ':' || tok == '@' || tok == '$') {
|
||||
next();
|
||||
}
|
||||
asm_expr(s1, &op->e);
|
||||
@ -261,20 +272,34 @@ static void parse_addr_operand(TCCState *s1, Operand *op)
|
||||
op->reg2 = -1;
|
||||
op->e.v = 0;
|
||||
op->e.sym = NULL;
|
||||
op->addr_mode = ADDR_OFF;
|
||||
op->reg_tok = 0;
|
||||
|
||||
skip('[');
|
||||
reg = arm64_parse_regvar(tok);
|
||||
if (reg >= 0 && reg < 32) {
|
||||
op->reg = reg;
|
||||
op->reg_tok = tok;
|
||||
next();
|
||||
/* Check for offset */
|
||||
if (tok == ',') {
|
||||
next();
|
||||
if (tok == '#' || tok == '@') next();
|
||||
if (tok == '#' || tok == '@' || tok == '$')
|
||||
next();
|
||||
asm_expr(s1, &op->e);
|
||||
}
|
||||
}
|
||||
skip(']');
|
||||
if (tok == '!') {
|
||||
op->addr_mode = ADDR_PRE;
|
||||
next();
|
||||
} else if (tok == ',') {
|
||||
op->addr_mode = ADDR_POST;
|
||||
next();
|
||||
if (tok == '#' || tok == '@' || tok == '$')
|
||||
next();
|
||||
asm_expr(s1, &op->e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate MOVZ instruction */
|
||||
@ -317,10 +342,22 @@ static void gen_movk(int rd, uint16_t imm, int shift, int is_64bit)
|
||||
static void gen_add_imm(int rd, int rn, uint32_t imm, int is_64bit, int setflags)
|
||||
{
|
||||
uint32_t instr = 0x11000000;
|
||||
uint32_t imm12;
|
||||
|
||||
if (is_64bit) instr |= (1 << 31);
|
||||
if (setflags) instr |= (1 << 29);
|
||||
instr |= ((imm >> 12) & 0x3) << 22;
|
||||
instr |= (imm & 0xFFF) << 10;
|
||||
|
||||
if (imm <= 0xFFF) {
|
||||
imm12 = imm;
|
||||
} else if (!(imm & 0xFFF) && (imm >> 12) <= 0xFFF) {
|
||||
instr |= 1 << 22;
|
||||
imm12 = imm >> 12;
|
||||
} else {
|
||||
tcc_error("add immediate out of range");
|
||||
return;
|
||||
}
|
||||
|
||||
instr |= imm12 << 10;
|
||||
instr |= (rn & 0x1F) << 5;
|
||||
instr |= rd & 0x1F;
|
||||
emit_instr32(instr);
|
||||
@ -330,10 +367,22 @@ static void gen_add_imm(int rd, int rn, uint32_t imm, int is_64bit, int setflags
|
||||
static void gen_sub_imm(int rd, int rn, uint32_t imm, int is_64bit, int setflags)
|
||||
{
|
||||
uint32_t instr = 0x51000000;
|
||||
uint32_t imm12;
|
||||
|
||||
if (is_64bit) instr |= (1 << 31);
|
||||
if (setflags) instr |= (1 << 29);
|
||||
instr |= ((imm >> 12) & 0x3) << 22;
|
||||
instr |= (imm & 0xFFF) << 10;
|
||||
|
||||
if (imm <= 0xFFF) {
|
||||
imm12 = imm;
|
||||
} else if (!(imm & 0xFFF) && (imm >> 12) <= 0xFFF) {
|
||||
instr |= 1 << 22;
|
||||
imm12 = imm >> 12;
|
||||
} else {
|
||||
tcc_error("sub immediate out of range");
|
||||
return;
|
||||
}
|
||||
|
||||
instr |= imm12 << 10;
|
||||
instr |= (rn & 0x1F) << 5;
|
||||
instr |= rd & 0x1F;
|
||||
emit_instr32(instr);
|
||||
@ -350,21 +399,44 @@ static void gen_dp_reg(uint32_t opcode, int rd, int rn, int rm, int is_64bit)
|
||||
emit_instr32(instr);
|
||||
}
|
||||
|
||||
/* Generate LDR/STR (immediate) */
|
||||
/* Generate LDR/STR (unsigned immediate) */
|
||||
static void gen_ldst_imm(uint32_t base_opcode, int rt, int rn,
|
||||
int32_t offset, int is_64bit, int size_log2)
|
||||
int32_t offset, int size_log2)
|
||||
{
|
||||
uint32_t instr = base_opcode;
|
||||
uint32_t imm12;
|
||||
|
||||
if (is_64bit) instr |= (1 << 30);
|
||||
if (offset < 0 || (offset & ((1 << size_log2) - 1)))
|
||||
tcc_error("invalid load/store offset");
|
||||
imm12 = offset >> size_log2;
|
||||
if (imm12 > 0xFFF)
|
||||
tcc_error("load/store offset out of range");
|
||||
instr |= (imm12 & 0xFFF) << 10;
|
||||
instr |= (rn & 0x1F) << 5;
|
||||
instr |= rt & 0x1F;
|
||||
emit_instr32(instr);
|
||||
}
|
||||
|
||||
/* Generate STP/LDP (signed immediate) */
|
||||
static void gen_ldst_pair(uint32_t base_opcode, int rt, int rt2, int rn,
|
||||
int32_t offset, int size_log2)
|
||||
{
|
||||
int32_t imm7;
|
||||
uint32_t instr = base_opcode;
|
||||
|
||||
if (offset & ((1 << size_log2) - 1))
|
||||
tcc_error("invalid pair load/store offset");
|
||||
imm7 = offset >> size_log2;
|
||||
if (imm7 < -64 || imm7 > 63)
|
||||
tcc_error("pair load/store offset out of range");
|
||||
|
||||
instr |= (imm7 & 0x7F) << 15;
|
||||
instr |= (rt2 & 0x1F) << 10;
|
||||
instr |= (rn & 0x1F) << 5;
|
||||
instr |= rt & 0x1F;
|
||||
emit_instr32(instr);
|
||||
}
|
||||
|
||||
/* Generate B (branch) */
|
||||
static void gen_b(int32_t offset)
|
||||
{
|
||||
@ -444,6 +516,61 @@ static void gen_mov_reg(int rd, int rm, int is_64bit)
|
||||
emit_instr32(instr);
|
||||
}
|
||||
|
||||
static int operand_is_sp(const Operand *op)
|
||||
{
|
||||
return op->reg_tok == TOK_ASM_sp;
|
||||
}
|
||||
|
||||
static int parse_sysreg_name(int t)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
if (t < TOK_IDENT)
|
||||
return -1;
|
||||
name = get_tok_str(t, NULL);
|
||||
if (!strcmp(name, "FPCR") || !strcmp(name, "fpcr"))
|
||||
return 0;
|
||||
if (!strcmp(name, "FPSR") || !strcmp(name, "fpsr"))
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void gen_mrs(int rt, int sysreg)
|
||||
{
|
||||
uint32_t instr;
|
||||
|
||||
switch (sysreg) {
|
||||
case 0:
|
||||
instr = 0xD53B4400;
|
||||
break;
|
||||
case 1:
|
||||
instr = 0xD53B4420;
|
||||
break;
|
||||
default:
|
||||
tcc_error("unsupported system register");
|
||||
return;
|
||||
}
|
||||
emit_instr32(instr | (rt & 0x1F));
|
||||
}
|
||||
|
||||
static void gen_msr(int rt, int sysreg)
|
||||
{
|
||||
uint32_t instr;
|
||||
|
||||
switch (sysreg) {
|
||||
case 0:
|
||||
instr = 0xD51B4400;
|
||||
break;
|
||||
case 1:
|
||||
instr = 0xD51B4420;
|
||||
break;
|
||||
default:
|
||||
tcc_error("unsupported system register");
|
||||
return;
|
||||
}
|
||||
emit_instr32(instr | (rt & 0x1F));
|
||||
}
|
||||
|
||||
/* Generate NOP */
|
||||
static void gen_nop(void)
|
||||
{
|
||||
@ -454,40 +581,46 @@ static void gen_nop(void)
|
||||
static void gen_shift(int rd, int rn, int rm_or_imm, int shift_type, int is_imm, int is_64bit)
|
||||
{
|
||||
uint32_t instr;
|
||||
int width = is_64bit ? 64 : 32;
|
||||
|
||||
if (is_imm) {
|
||||
/* Shift by immediate */
|
||||
switch (shift_type) {
|
||||
case 0: /* LSL */
|
||||
instr = is_64bit ? 0xD3600000 : 0x53000000;
|
||||
/* For LSL, the immediate is encoded as (64 - imm) & 0x3F for 64-bit */
|
||||
if (is_64bit) {
|
||||
instr |= ((64 - rm_or_imm) & 0x3F) << 10;
|
||||
} else {
|
||||
instr |= ((32 - rm_or_imm) & 0x1F) << 10;
|
||||
if (rm_or_imm < 0 || rm_or_imm >= width) {
|
||||
tcc_error("shift immediate out of range");
|
||||
return;
|
||||
}
|
||||
instr = is_64bit ? 0xD3400000 : 0x53000000;
|
||||
instr |= ((width - rm_or_imm) & (width - 1)) << 16;
|
||||
instr |= (width - 1 - rm_or_imm) << 10;
|
||||
break;
|
||||
case 1: /* LSR */
|
||||
instr = is_64bit ? 0xD3600000 : 0x53000000;
|
||||
instr |= (1 << 22);
|
||||
if (is_64bit) {
|
||||
instr |= ((64 - rm_or_imm) & 0x3F) << 10;
|
||||
} else {
|
||||
instr |= ((32 - rm_or_imm) & 0x1F) << 10;
|
||||
if (rm_or_imm < 0 || rm_or_imm >= width) {
|
||||
tcc_error("shift immediate out of range");
|
||||
return;
|
||||
}
|
||||
instr = is_64bit ? 0xD3400000 : 0x53000000;
|
||||
instr |= rm_or_imm << 16;
|
||||
instr |= (width - 1) << 10;
|
||||
break;
|
||||
case 2: /* ASR */
|
||||
instr = is_64bit ? 0xD3600000 : 0x53000000;
|
||||
instr |= (2 << 22);
|
||||
if (is_64bit) {
|
||||
instr |= ((64 - rm_or_imm) & 0x3F) << 10;
|
||||
} else {
|
||||
instr |= ((32 - rm_or_imm) & 0x1F) << 10;
|
||||
if (rm_or_imm < 0 || rm_or_imm >= width) {
|
||||
tcc_error("shift immediate out of range");
|
||||
return;
|
||||
}
|
||||
instr = is_64bit ? 0x93400000 : 0x13000000;
|
||||
instr |= rm_or_imm << 16;
|
||||
instr |= (width - 1) << 10;
|
||||
break;
|
||||
case 3: /* ROR */
|
||||
instr = is_64bit ? 0x93C00000 : 0x13C00000;
|
||||
instr |= (rm_or_imm & 0x1F) << 10;
|
||||
if (rm_or_imm < 0 || rm_or_imm >= width) {
|
||||
tcc_error("shift immediate out of range");
|
||||
return;
|
||||
}
|
||||
instr = is_64bit ? 0x93C00000 : 0x13800000;
|
||||
instr |= (rn & 0x1F) << 16;
|
||||
instr |= (rm_or_imm & (width - 1)) << 10;
|
||||
break;
|
||||
default:
|
||||
tcc_error("unknown shift type");
|
||||
@ -499,21 +632,23 @@ static void gen_shift(int rd, int rn, int rm_or_imm, int shift_type, int is_imm,
|
||||
/* Shift by register */
|
||||
switch (shift_type) {
|
||||
case 0: /* LSL */
|
||||
instr = is_64bit ? 0x1AC02000 : 0x1AC02000;
|
||||
instr = 0x1AC02000;
|
||||
break;
|
||||
case 1: /* LSR */
|
||||
instr = is_64bit ? 0x1AC02400 : 0x1AC02400;
|
||||
instr = 0x1AC02400;
|
||||
break;
|
||||
case 2: /* ASR */
|
||||
instr = is_64bit ? 0x1AC02800 : 0x1AC02800;
|
||||
instr = 0x1AC02800;
|
||||
break;
|
||||
case 3: /* ROR */
|
||||
instr = is_64bit ? 0x1AC02C00 : 0x1AC02C00;
|
||||
instr = 0x1AC02C00;
|
||||
break;
|
||||
default:
|
||||
tcc_error("unknown shift type");
|
||||
return;
|
||||
}
|
||||
if (is_64bit)
|
||||
instr |= 1U << 31;
|
||||
instr |= (rm_or_imm & 0x1F) << 16;
|
||||
instr |= (rn & 0x1F) << 5;
|
||||
instr |= rd & 0x1F;
|
||||
@ -674,11 +809,18 @@ static void asm_mov(TCCState *s1)
|
||||
|
||||
if (op2.type & OP_IM) {
|
||||
/* Handle immediate: mov x0, #123 */
|
||||
if (operand_is_sp(&op1)) {
|
||||
tcc_error("cannot move an immediate into sp");
|
||||
return;
|
||||
}
|
||||
gen_mov_imm(rd, op2.e.v, is_64bit);
|
||||
} else if (op2.type & OP_REG) {
|
||||
/* Handle register: mov x0, x1 */
|
||||
rn = op2.reg;
|
||||
gen_mov_reg(rd, rn, is_64bit);
|
||||
if (operand_is_sp(&op1) || operand_is_sp(&op2))
|
||||
gen_add_imm(rd, rn, 0, 1, 0);
|
||||
else
|
||||
gen_mov_reg(rd, rn, is_64bit);
|
||||
} else {
|
||||
tcc_error("invalid operand for mov");
|
||||
}
|
||||
@ -758,7 +900,6 @@ static void asm_ldst(TCCState *s1, int token)
|
||||
Operand op1, op2;
|
||||
int rt, rn;
|
||||
int32_t offset = 0;
|
||||
int is_64bit = 1;
|
||||
int size_log2 = 3;
|
||||
uint32_t base_opcode;
|
||||
|
||||
@ -772,49 +913,49 @@ static void asm_ldst(TCCState *s1, int token)
|
||||
|
||||
switch (token) {
|
||||
case TOK_ASM_ldr:
|
||||
base_opcode = 0xB9400000;
|
||||
if (op1.reg_type & REG_X) {
|
||||
is_64bit = 1;
|
||||
base_opcode = 0xF9400000;
|
||||
size_log2 = 3;
|
||||
} else if (op1.reg_type & REG_W) {
|
||||
is_64bit = 0;
|
||||
base_opcode = 0xB9400000;
|
||||
size_log2 = 2;
|
||||
} else if (op1.reg_type & REG_D) {
|
||||
base_opcode = 0xFD400000;
|
||||
size_log2 = 3;
|
||||
} else {
|
||||
tcc_error("ldr requires a w or x register");
|
||||
tcc_error("ldr requires a w, x, or d register");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_ldrb:
|
||||
base_opcode = 0x39400000;
|
||||
is_64bit = 0;
|
||||
size_log2 = 0;
|
||||
break;
|
||||
case TOK_ASM_ldrh:
|
||||
base_opcode = 0x79400000;
|
||||
is_64bit = 0;
|
||||
size_log2 = 1;
|
||||
break;
|
||||
case TOK_ASM_str:
|
||||
base_opcode = 0xB9000000;
|
||||
if (op1.reg_type & REG_X) {
|
||||
is_64bit = 1;
|
||||
base_opcode = 0xF9000000;
|
||||
size_log2 = 3;
|
||||
} else if (op1.reg_type & REG_W) {
|
||||
is_64bit = 0;
|
||||
base_opcode = 0xB9000000;
|
||||
size_log2 = 2;
|
||||
} else if (op1.reg_type & REG_D) {
|
||||
base_opcode = 0xFD000000;
|
||||
size_log2 = 3;
|
||||
} else {
|
||||
tcc_error("str requires a w or x register");
|
||||
tcc_error("str requires a w, x, or d register");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TOK_ASM_strb:
|
||||
base_opcode = 0x39000000;
|
||||
is_64bit = 0;
|
||||
size_log2 = 0;
|
||||
break;
|
||||
case TOK_ASM_strh:
|
||||
base_opcode = 0x79000000;
|
||||
is_64bit = 0;
|
||||
size_log2 = 1;
|
||||
break;
|
||||
default:
|
||||
@ -822,7 +963,81 @@ static void asm_ldst(TCCState *s1, int token)
|
||||
return;
|
||||
}
|
||||
|
||||
gen_ldst_imm(base_opcode, rt, rn, offset, is_64bit, size_log2);
|
||||
if (op2.addr_mode != ADDR_OFF)
|
||||
tcc_error("only offset addressing is implemented for ldr/str");
|
||||
gen_ldst_imm(base_opcode, rt, rn, offset, size_log2);
|
||||
}
|
||||
|
||||
static void asm_ldst_pair(TCCState *s1, int token)
|
||||
{
|
||||
Operand op1, op2, op3;
|
||||
uint32_t base_opcode;
|
||||
int size_log2 = 3;
|
||||
|
||||
parse_operand(s1, &op1);
|
||||
if (tok == ',')
|
||||
next();
|
||||
parse_operand(s1, &op2);
|
||||
if (tok == ',')
|
||||
next();
|
||||
parse_operand(s1, &op3);
|
||||
|
||||
if (!(op3.type & OP_ADDR))
|
||||
tcc_error("pair load/store requires an address operand");
|
||||
|
||||
if ((op1.reg_type & REG_X) && (op2.reg_type & REG_X)) {
|
||||
if (token == TOK_ASM_stp) {
|
||||
base_opcode = op3.addr_mode == ADDR_PRE ? 0xA9800000 :
|
||||
op3.addr_mode == ADDR_POST ? 0xA8800000 :
|
||||
0xA9000000;
|
||||
} else {
|
||||
base_opcode = op3.addr_mode == ADDR_PRE ? 0xA9C00000 :
|
||||
op3.addr_mode == ADDR_POST ? 0xA8C00000 :
|
||||
0xA9400000;
|
||||
}
|
||||
} else if ((op1.reg_type & REG_D) && (op2.reg_type & REG_D)) {
|
||||
if (token == TOK_ASM_stp) {
|
||||
base_opcode = op3.addr_mode == ADDR_PRE ? 0x6D800000 :
|
||||
op3.addr_mode == ADDR_POST ? 0x6C800000 :
|
||||
0x6D000000;
|
||||
} else {
|
||||
base_opcode = op3.addr_mode == ADDR_PRE ? 0x6DC00000 :
|
||||
op3.addr_mode == ADDR_POST ? 0x6CC00000 :
|
||||
0x6D400000;
|
||||
}
|
||||
} else {
|
||||
tcc_error("stp/ldp requires matching x or d registers");
|
||||
return;
|
||||
}
|
||||
|
||||
gen_ldst_pair(base_opcode, op1.reg, op2.reg, op3.reg, op3.e.v, size_log2);
|
||||
}
|
||||
|
||||
static void asm_sysreg(TCCState *s1, int token)
|
||||
{
|
||||
Operand op;
|
||||
int sysreg;
|
||||
|
||||
if (token == TOK_ASM_mrs) {
|
||||
parse_operand(s1, &op);
|
||||
if (tok == ',')
|
||||
next();
|
||||
sysreg = parse_sysreg_name(tok);
|
||||
if (sysreg < 0)
|
||||
tcc_error("unsupported system register");
|
||||
next();
|
||||
gen_mrs(op.reg, sysreg);
|
||||
return;
|
||||
}
|
||||
|
||||
sysreg = parse_sysreg_name(tok);
|
||||
if (sysreg < 0)
|
||||
tcc_error("unsupported system register");
|
||||
next();
|
||||
if (tok == ',')
|
||||
next();
|
||||
parse_operand(s1, &op);
|
||||
gen_msr(op.reg, sysreg);
|
||||
}
|
||||
|
||||
/* Handle branch instructions */
|
||||
@ -850,20 +1065,22 @@ static void asm_branch(TCCState *s1, int token)
|
||||
/* Check for conditional branch */
|
||||
cond = -1;
|
||||
switch (token) {
|
||||
case TOK_ASM_b_eq: cond = 0; break;
|
||||
case TOK_ASM_b_ne: cond = 1; break;
|
||||
case TOK_ASM_b_cs: cond = 2; break;
|
||||
case TOK_ASM_b_cc: cond = 3; break;
|
||||
case TOK_ASM_b_mi: cond = 4; break;
|
||||
case TOK_ASM_b_pl: cond = 5; break;
|
||||
case TOK_ASM_b_vs: cond = 6; break;
|
||||
case TOK_ASM_b_vc: cond = 7; break;
|
||||
case TOK_ASM_b_hi: cond = 8; break;
|
||||
case TOK_ASM_b_ls: cond = 9; break;
|
||||
case TOK_ASM_b_ge: cond = 10; break;
|
||||
case TOK_ASM_b_lt: cond = 11; break;
|
||||
case TOK_ASM_b_gt: cond = 12; break;
|
||||
case TOK_ASM_b_le: cond = 13; break;
|
||||
case TOK_ASM_beq: cond = 0; break;
|
||||
case TOK_ASM_bne: cond = 1; break;
|
||||
case TOK_ASM_bcs:
|
||||
case TOK_ASM_bhs: cond = 2; break;
|
||||
case TOK_ASM_bcc:
|
||||
case TOK_ASM_blo: cond = 3; break;
|
||||
case TOK_ASM_bmi: cond = 4; break;
|
||||
case TOK_ASM_bpl: cond = 5; break;
|
||||
case TOK_ASM_bvs: cond = 6; break;
|
||||
case TOK_ASM_bvc: cond = 7; break;
|
||||
case TOK_ASM_bhi: cond = 8; break;
|
||||
case TOK_ASM_bls: cond = 9; break;
|
||||
case TOK_ASM_bge: cond = 10; break;
|
||||
case TOK_ASM_blt: cond = 11; break;
|
||||
case TOK_ASM_bgt: cond = 12; break;
|
||||
case TOK_ASM_ble: cond = 13; break;
|
||||
}
|
||||
|
||||
if (cond >= 0) {
|
||||
@ -890,20 +1107,22 @@ static void asm_branch(TCCState *s1, int token)
|
||||
/* Check for conditional branch */
|
||||
cond = -1;
|
||||
switch (token) {
|
||||
case TOK_ASM_b_eq: cond = 0; break;
|
||||
case TOK_ASM_b_ne: cond = 1; break;
|
||||
case TOK_ASM_b_cs: cond = 2; break;
|
||||
case TOK_ASM_b_cc: cond = 3; break;
|
||||
case TOK_ASM_b_mi: cond = 4; break;
|
||||
case TOK_ASM_b_pl: cond = 5; break;
|
||||
case TOK_ASM_b_vs: cond = 6; break;
|
||||
case TOK_ASM_b_vc: cond = 7; break;
|
||||
case TOK_ASM_b_hi: cond = 8; break;
|
||||
case TOK_ASM_b_ls: cond = 9; break;
|
||||
case TOK_ASM_b_ge: cond = 10; break;
|
||||
case TOK_ASM_b_lt: cond = 11; break;
|
||||
case TOK_ASM_b_gt: cond = 12; break;
|
||||
case TOK_ASM_b_le: cond = 13; break;
|
||||
case TOK_ASM_beq: cond = 0; break;
|
||||
case TOK_ASM_bne: cond = 1; break;
|
||||
case TOK_ASM_bcs:
|
||||
case TOK_ASM_bhs: cond = 2; break;
|
||||
case TOK_ASM_bcc:
|
||||
case TOK_ASM_blo: cond = 3; break;
|
||||
case TOK_ASM_bmi: cond = 4; break;
|
||||
case TOK_ASM_bpl: cond = 5; break;
|
||||
case TOK_ASM_bvs: cond = 6; break;
|
||||
case TOK_ASM_bvc: cond = 7; break;
|
||||
case TOK_ASM_bhi: cond = 8; break;
|
||||
case TOK_ASM_bls: cond = 9; break;
|
||||
case TOK_ASM_bge: cond = 10; break;
|
||||
case TOK_ASM_blt: cond = 11; break;
|
||||
case TOK_ASM_bgt: cond = 12; break;
|
||||
case TOK_ASM_ble: cond = 13; break;
|
||||
}
|
||||
|
||||
if (cond >= 0) {
|
||||
@ -1052,25 +1271,32 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
||||
asm_ldst(s1, opcode);
|
||||
break;
|
||||
|
||||
case TOK_ASM_ldp:
|
||||
case TOK_ASM_stp:
|
||||
asm_ldst_pair(s1, opcode);
|
||||
break;
|
||||
|
||||
case TOK_ASM_b:
|
||||
case TOK_ASM_bl:
|
||||
case TOK_ASM_br:
|
||||
case TOK_ASM_blr:
|
||||
case TOK_ASM_ret:
|
||||
case TOK_ASM_b_eq:
|
||||
case TOK_ASM_b_ne:
|
||||
case TOK_ASM_b_cs:
|
||||
case TOK_ASM_b_cc:
|
||||
case TOK_ASM_b_mi:
|
||||
case TOK_ASM_b_pl:
|
||||
case TOK_ASM_b_vs:
|
||||
case TOK_ASM_b_vc:
|
||||
case TOK_ASM_b_hi:
|
||||
case TOK_ASM_b_ls:
|
||||
case TOK_ASM_b_ge:
|
||||
case TOK_ASM_b_lt:
|
||||
case TOK_ASM_b_gt:
|
||||
case TOK_ASM_b_le:
|
||||
case TOK_ASM_beq:
|
||||
case TOK_ASM_bne:
|
||||
case TOK_ASM_bcs:
|
||||
case TOK_ASM_bhs:
|
||||
case TOK_ASM_bcc:
|
||||
case TOK_ASM_blo:
|
||||
case TOK_ASM_bmi:
|
||||
case TOK_ASM_bpl:
|
||||
case TOK_ASM_bvs:
|
||||
case TOK_ASM_bvc:
|
||||
case TOK_ASM_bhi:
|
||||
case TOK_ASM_bls:
|
||||
case TOK_ASM_bge:
|
||||
case TOK_ASM_blt:
|
||||
case TOK_ASM_bgt:
|
||||
case TOK_ASM_ble:
|
||||
asm_branch(s1, opcode);
|
||||
break;
|
||||
|
||||
@ -1085,6 +1311,11 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
||||
asm_move_wide(s1, opcode);
|
||||
break;
|
||||
|
||||
case TOK_ASM_mrs:
|
||||
case TOK_ASM_msr:
|
||||
asm_sysreg(s1, opcode);
|
||||
break;
|
||||
|
||||
case TOK_ASM_isb:
|
||||
case TOK_ASM_dsb:
|
||||
case TOK_ASM_dmb:
|
||||
|
||||
@ -374,6 +374,8 @@
|
||||
DEF_ASM(adrp)
|
||||
|
||||
/* System instructions */
|
||||
DEF_ASM(mrs)
|
||||
DEF_ASM(msr)
|
||||
DEF_ASM(nop)
|
||||
DEF_ASM(wfi)
|
||||
DEF_ASM(wfe)
|
||||
|
||||
@ -13,18 +13,25 @@
|
||||
|
||||
.globl __chkstk
|
||||
__chkstk:
|
||||
.long 0x910003f0
|
||||
.long 0xd37cedf1
|
||||
.long 0xb4000131
|
||||
.long 0xf1400620
|
||||
.long 0x540000a9
|
||||
.long 0xd1400610
|
||||
.long 0xf940021f
|
||||
.long 0xd1400631
|
||||
.long 0x17fffffb
|
||||
.long 0xcb110210
|
||||
.long 0xf940021f
|
||||
.long 0xd65f03c0
|
||||
/* Windows ARM64 stack probing helper.
|
||||
arm64-gen.c passes the requested frame size in x15, scaled in 16-byte
|
||||
units. Probe one 4 KiB page at a time and leave SP unchanged; the caller
|
||||
subtracts SP after the probe returns. */
|
||||
mov x16, sp
|
||||
lsl x17, x15, 4
|
||||
cbz x17, L_chkstk_done
|
||||
L_chkstk_loop:
|
||||
subs x0, x17, 4096
|
||||
bls L_chkstk_tail
|
||||
sub x16, x16, 4096
|
||||
ldr xzr, [x16]
|
||||
sub x17, x17, 4096
|
||||
b L_chkstk_loop
|
||||
L_chkstk_tail:
|
||||
sub x16, x16, x17
|
||||
ldr xzr, [x16]
|
||||
L_chkstk_done:
|
||||
ret
|
||||
|
||||
.globl _(tinyc_getbp)
|
||||
_(tinyc_getbp):
|
||||
@ -33,53 +40,57 @@ _(tinyc_getbp):
|
||||
|
||||
.globl _(mingw_getsp)
|
||||
_(mingw_getsp):
|
||||
.long 0x910003e0
|
||||
.long 0xd65f03c0
|
||||
mov x0, sp
|
||||
ret
|
||||
|
||||
.globl _(__mingw_setjmp)
|
||||
_(__mingw_setjmp):
|
||||
.long 0xf900001f
|
||||
.long 0xa9015013
|
||||
.long 0xa9025815
|
||||
.long 0xa9036017
|
||||
.long 0xa9046819
|
||||
.long 0xa905701b
|
||||
.long 0xa906781d
|
||||
.long 0x910003e2
|
||||
.long 0xf9003802
|
||||
.long 0xd53b4402
|
||||
.long 0xb9007802
|
||||
.long 0xd53b4422
|
||||
.long 0xb9007c02
|
||||
.long 0x6d082408
|
||||
.long 0x6d092c0a
|
||||
.long 0x6d0a340c
|
||||
.long 0x6d0b3c0e
|
||||
.long 0xd2800000
|
||||
.long 0xd65f03c0
|
||||
/* _JUMP_BUFFER layout matches win32/include/setjmp.h for _ARM64_:
|
||||
0x00 Frame, 0x08 Reserved, 0x10-0x68 X19-X30, 0x70 Sp,
|
||||
0x78 Fpcr/Fpsr, 0x80-0xB8 D8-D15. */
|
||||
str xzr, [x0] /* Frame = 0 */
|
||||
stp x19, x20, [x0, 16]
|
||||
stp x21, x22, [x0, 32]
|
||||
stp x23, x24, [x0, 48]
|
||||
stp x25, x26, [x0, 64]
|
||||
stp x27, x28, [x0, 80]
|
||||
stp x29, x30, [x0, 96]
|
||||
mov x2, sp
|
||||
str x2, [x0, 112] /* Sp */
|
||||
mrs x2, FPCR
|
||||
str w2, [x0, 120] /* Fpcr */
|
||||
mrs x2, FPSR
|
||||
str w2, [x0, 124] /* Fpsr */
|
||||
stp d8, d9, [x0, 128]
|
||||
stp d10, d11, [x0, 144]
|
||||
stp d12, d13, [x0, 160]
|
||||
stp d14, d15, [x0, 176]
|
||||
mov x0, 0
|
||||
ret
|
||||
|
||||
.globl _(__mingw_longjmp)
|
||||
_(__mingw_longjmp):
|
||||
.long 0xa9415013
|
||||
.long 0xa9425815
|
||||
.long 0xa9436017
|
||||
.long 0xa9446819
|
||||
.long 0xa945701b
|
||||
.long 0xa946781d
|
||||
.long 0xf9403802
|
||||
.long 0x9100005f
|
||||
.long 0xb9407802
|
||||
.long 0xd51b4402
|
||||
.long 0xb9407c02
|
||||
.long 0xd51b4422
|
||||
.long 0x6d482408
|
||||
.long 0x6d492c0a
|
||||
.long 0x6d4a340c
|
||||
.long 0x6d4b3c0e
|
||||
.long 0xaa0103e0
|
||||
.long 0xb5000040
|
||||
.long 0xd2800020
|
||||
.long 0xd65f03c0
|
||||
ldp x19, x20, [x0, 16]
|
||||
ldp x21, x22, [x0, 32]
|
||||
ldp x23, x24, [x0, 48]
|
||||
ldp x25, x26, [x0, 64]
|
||||
ldp x27, x28, [x0, 80]
|
||||
ldp x29, x30, [x0, 96]
|
||||
ldr x2, [x0, 112] /* Sp */
|
||||
mov sp, x2
|
||||
ldr w2, [x0, 120] /* Fpcr */
|
||||
msr FPCR, x2
|
||||
ldr w2, [x0, 124] /* Fpsr */
|
||||
msr FPSR, x2
|
||||
ldp d8, d9, [x0, 128]
|
||||
ldp d10, d11, [x0, 144]
|
||||
ldp d12, d13, [x0, 160]
|
||||
ldp d14, d15, [x0, 176]
|
||||
mov x0, x1
|
||||
cbnz x0, L_longjmp_done
|
||||
mov x0, 1
|
||||
L_longjmp_done:
|
||||
ret
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#elif !defined(__x86_64__)
|
||||
|
||||
@ -3,32 +3,32 @@
|
||||
.global arm64_call_with_dregs
|
||||
|
||||
arm64_call_with_dregs:
|
||||
stp x29, x30, [sp, #-32]!
|
||||
stp x19, x20, [sp, #16]
|
||||
stp x29, x30, [sp, -32]!
|
||||
stp x19, x20, [sp, 16]
|
||||
mov x29, sp
|
||||
mov x19, x1
|
||||
|
||||
ldr d8, [x0, #0]
|
||||
ldr d9, [x0, #8]
|
||||
ldr d10, [x0, #16]
|
||||
ldr d11, [x0, #24]
|
||||
ldr d12, [x0, #32]
|
||||
ldr d13, [x0, #40]
|
||||
ldr d14, [x0, #48]
|
||||
ldr d15, [x0, #56]
|
||||
ldr d8, [x0, 0]
|
||||
ldr d9, [x0, 8]
|
||||
ldr d10, [x0, 16]
|
||||
ldr d11, [x0, 24]
|
||||
ldr d12, [x0, 32]
|
||||
ldr d13, [x0, 40]
|
||||
ldr d14, [x0, 48]
|
||||
ldr d15, [x0, 56]
|
||||
|
||||
mov x0, x3
|
||||
blr x2
|
||||
|
||||
str d8, [x19, #0]
|
||||
str d9, [x19, #8]
|
||||
str d10, [x19, #16]
|
||||
str d11, [x19, #24]
|
||||
str d12, [x19, #32]
|
||||
str d13, [x19, #40]
|
||||
str d14, [x19, #48]
|
||||
str d15, [x19, #56]
|
||||
str d8, [x19, 0]
|
||||
str d9, [x19, 8]
|
||||
str d10, [x19, 16]
|
||||
str d11, [x19, 24]
|
||||
str d12, [x19, 32]
|
||||
str d13, [x19, 40]
|
||||
str d14, [x19, 48]
|
||||
str d15, [x19, 56]
|
||||
|
||||
ldp x19, x20, [sp, #16]
|
||||
ldp x29, x30, [sp], #32
|
||||
ldp x19, x20, [sp, 16]
|
||||
ldp x29, x30, [sp], 32
|
||||
ret
|
||||
|
||||
Loading…
Reference in New Issue
Block a user