mirror of
https://github.com/mirror/tinycc.git
synced 2025-02-26 08:00:09 +08:00
riscv: Implement long double support
for the implementation of operations we can reuse the ones from lib/lib-arm64.c, risc-v long double is also float128. Also implement ggoto, and PDIV, and use t0 in load/store as temporary register if necessary, not one given by get_reg (the latter can destroy assignments of long double parameters in function calls that are already set up). This let's us compile tcc.c and tcctest.c, though both don't yet work.
This commit is contained in:
parent
2616c6b230
commit
2668eda595
@ -43,7 +43,7 @@ I386_O = libtcc1.o alloca86.o alloca86-bt.o
|
|||||||
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o
|
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o
|
||||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o
|
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o
|
||||||
ARM64_O = lib-arm64.o
|
ARM64_O = lib-arm64.o
|
||||||
RISCV64_O =
|
RISCV64_O = lib-arm64.o
|
||||||
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
|
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
|
||||||
|
|
||||||
OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
|
OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
|
||||||
|
@ -24,10 +24,12 @@ void *memcpy(void*,void*,__SIZE_TYPE__);
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __riscv
|
||||||
void __clear_cache(void *beg, void *end)
|
void __clear_cache(void *beg, void *end)
|
||||||
{
|
{
|
||||||
__arm64_clear_cache(beg, end);
|
__arm64_clear_cache(beg, end);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint64_t x0, x1;
|
uint64_t x0, x1;
|
||||||
|
121
riscv64-gen.c
121
riscv64-gen.c
@ -95,11 +95,17 @@ ST_FUNC void o(unsigned int c)
|
|||||||
ind = ind1;
|
ind = ind1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void EIu(uint32_t opcode, uint32_t func3,
|
||||||
|
uint32_t rd, uint32_t rs1, uint32_t imm)
|
||||||
|
{
|
||||||
|
o(opcode | (func3 << 12) | (rd << 7) | (rs1 << 15) | (imm << 20));
|
||||||
|
}
|
||||||
|
|
||||||
static void EI(uint32_t opcode, uint32_t func3,
|
static void EI(uint32_t opcode, uint32_t func3,
|
||||||
uint32_t rd, uint32_t rs1, uint32_t imm)
|
uint32_t rd, uint32_t rs1, uint32_t imm)
|
||||||
{
|
{
|
||||||
assert(! ((imm + (1 << 11)) >> 12));
|
assert(! ((imm + (1 << 11)) >> 12));
|
||||||
o(opcode | (func3 << 12) | (rd << 7) | (rs1 << 15) | (imm << 20));
|
EIu(opcode, func3, rd, rs1, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ES(uint32_t opcode, uint32_t func3,
|
static void ES(uint32_t opcode, uint32_t func3,
|
||||||
@ -157,7 +163,7 @@ ST_FUNC void load(int r, SValue *sv)
|
|||||||
if (fc != sv->c.i)
|
if (fc != sv->c.i)
|
||||||
tcc_error("unimp: load1(giant local ofs) (0x%llx)", (long long)sv->c.i);
|
tcc_error("unimp: load1(giant local ofs) (0x%llx)", (long long)sv->c.i);
|
||||||
if (((unsigned)fc + (1 << 11)) >> 12) {
|
if (((unsigned)fc + (1 << 11)) >> 12) {
|
||||||
br = is_ireg(r) ? rr : ireg(get_reg(RC_INT));
|
br = is_ireg(r) ? rr : 5;
|
||||||
o(0x37 | (br << 7) | ((0x800 + fc) & 0xfffff000)); //lui BR, upper(fc)
|
o(0x37 | (br << 7) | ((0x800 + fc) & 0xfffff000)); //lui BR, upper(fc)
|
||||||
o(0x33 | (br << 7) | (br << 15) | (8 << 20)); // add BR, BR, s0
|
o(0x33 | (br << 7) | (br << 15) | (8 << 20)); // add BR, BR, s0
|
||||||
fc = fc << 20 >> 20;
|
fc = fc << 20 >> 20;
|
||||||
@ -182,13 +188,13 @@ ST_FUNC void load(int r, SValue *sv)
|
|||||||
}
|
}
|
||||||
label.c = 0; /* force new local ELF symbol */
|
label.c = 0; /* force new local ELF symbol */
|
||||||
put_extern_sym(&label, cur_text_section, ind, 0);
|
put_extern_sym(&label, cur_text_section, ind, 0);
|
||||||
tempr = is_ireg(r) ? rr : ireg(get_reg(RC_INT));
|
tempr = is_ireg(r) ? rr : 5;
|
||||||
o(0x17 | (tempr << 7)); // auipc TR, 0 %pcrel_hi(sym)+addend
|
o(0x17 | (tempr << 7)); // auipc TR, 0 %pcrel_hi(sym)+addend
|
||||||
greloca(cur_text_section, &label, ind,
|
greloca(cur_text_section, &label, ind,
|
||||||
R_RISCV_PCREL_LO12_I, 0);
|
R_RISCV_PCREL_LO12_I, 0);
|
||||||
EI(opcode, func3, rr, tempr, fc); // l[bhwd][u] RR, fc(TR)
|
EI(opcode, func3, rr, tempr, fc); // l[bhwd][u] RR, fc(TR)
|
||||||
} else if (v == VT_LLOCAL) {
|
} else if (v == VT_LLOCAL) {
|
||||||
int br = 8, tempr = is_ireg(r) ? rr : ireg(get_reg(RC_INT));
|
int br = 8, tempr = is_ireg(r) ? rr : 5;
|
||||||
if (fc != sv->c.i)
|
if (fc != sv->c.i)
|
||||||
tcc_error("unimp: load2(giant local ofs) (0x%llx)", (long long)sv->c.i);
|
tcc_error("unimp: load2(giant local ofs) (0x%llx)", (long long)sv->c.i);
|
||||||
if (((unsigned)fc + (1 << 11)) >> 12) {
|
if (((unsigned)fc + (1 << 11)) >> 12) {
|
||||||
@ -333,7 +339,7 @@ ST_FUNC void store(int r, SValue *sv)
|
|||||||
if (fc != sv->c.i)
|
if (fc != sv->c.i)
|
||||||
tcc_error("unimp: store(giant local off) (0x%llx)", (long long)sv->c.i);
|
tcc_error("unimp: store(giant local off) (0x%llx)", (long long)sv->c.i);
|
||||||
if (((unsigned)fc + (1 << 11)) >> 12) {
|
if (((unsigned)fc + (1 << 11)) >> 12) {
|
||||||
br = ireg(get_reg(RC_INT));
|
br = 5; // t0
|
||||||
o(0x37 | (br << 7) | ((0x800 + fc) & 0xfffff000)); //lui BR, upper(fc)
|
o(0x37 | (br << 7) | ((0x800 + fc) & 0xfffff000)); //lui BR, upper(fc)
|
||||||
o(0x33 | (br << 7) | (br << 15) | (8 << 20)); // add BR, BR, s0
|
o(0x33 | (br << 7) | (br << 15) | (8 << 20)); // add BR, BR, s0
|
||||||
fc = fc << 20 >> 20;
|
fc = fc << 20 >> 20;
|
||||||
@ -353,13 +359,13 @@ ST_FUNC void store(int r, SValue *sv)
|
|||||||
else
|
else
|
||||||
ES(0x23, size == 1 ? 0 : size == 2 ? 1 : size == 4 ? 2 : 3,
|
ES(0x23, size == 1 ? 0 : size == 2 ? 1 : size == 4 ? 2 : 3,
|
||||||
ptrreg, rr, fc); // s[bhwd] RR, fc(PTRREG)
|
ptrreg, rr, fc); // s[bhwd] RR, fc(PTRREG)
|
||||||
} else if (sv->r == (VT_CONST | VT_SYM | VT_LVAL)) {
|
} else if ((sv->r & ~VT_LVAL_TYPE) == (VT_CONST | VT_SYM | VT_LVAL)) {
|
||||||
static Sym label;
|
static Sym label;
|
||||||
int tempr, addend = 0;
|
int tempr, addend = 0;
|
||||||
if (1 || ((unsigned)fc + (1 << 11)) >> 12)
|
if (1 || ((unsigned)fc + (1 << 11)) >> 12)
|
||||||
addend = fc, fc = 0;
|
addend = fc, fc = 0;
|
||||||
|
|
||||||
tempr = ireg(get_reg(RC_INT));
|
tempr = 5; // t0
|
||||||
greloca(cur_text_section, sv->sym, ind,
|
greloca(cur_text_section, sv->sym, ind,
|
||||||
R_RISCV_PCREL_HI20, addend);
|
R_RISCV_PCREL_HI20, addend);
|
||||||
if (!label.v) {
|
if (!label.v) {
|
||||||
@ -380,23 +386,24 @@ ST_FUNC void store(int r, SValue *sv)
|
|||||||
tcc_error("implement me: %s(!local)", __FUNCTION__);
|
tcc_error("implement me: %s(!local)", __FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gcall(void)
|
static void gcall_or_jmp(int docall)
|
||||||
{
|
{
|
||||||
|
int tr = docall ? 1 : 5; // ra or t0
|
||||||
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST &&
|
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST &&
|
||||||
((vtop->r & VT_SYM) && vtop->c.i == (int)vtop->c.i)) {
|
((vtop->r & VT_SYM) && vtop->c.i == (int)vtop->c.i)) {
|
||||||
/* constant symbolic case -> simple relocation */
|
/* constant symbolic case -> simple relocation */
|
||||||
greloca(cur_text_section, vtop->sym, ind,
|
greloca(cur_text_section, vtop->sym, ind,
|
||||||
R_RISCV_CALL_PLT, (int)vtop->c.i);
|
R_RISCV_CALL_PLT, (int)vtop->c.i);
|
||||||
o(0x17 | (1 << 7)); // auipc ra, 0 %call(func)
|
o(0x17 | (tr << 7)); // auipc TR, 0 %call(func)
|
||||||
o(0x80e7); // jalr ra, 0 %call(func)
|
EI(0x67, 0, tr, tr, 0);// jalr TR, r(TR)
|
||||||
} else if (vtop->r < VT_CONST) {
|
} else if (vtop->r < VT_CONST) {
|
||||||
int r = ireg(vtop->r);
|
int r = ireg(vtop->r);
|
||||||
EI(0x67, 0, 1, r, 0); // jalr ra, 0(R)
|
EI(0x67, 0, tr, r, 0); // jalr TR, 0(R)
|
||||||
} else {
|
} else {
|
||||||
int r = TREG_RA;
|
int r = TREG_RA;
|
||||||
load(r, vtop);
|
load(r, vtop);
|
||||||
r = ireg(r);
|
r = ireg(r);
|
||||||
EI(0x67, 0, 1, r, 0); // jalr ra, 0(R)
|
EI(0x67, 0, tr, r, 0); // jalr TR, 0(R)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +543,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
vrotb(nb_args + 1);
|
vrotb(nb_args + 1);
|
||||||
gcall();
|
gcall_or_jmp(1);
|
||||||
vtop -= nb_args + 1;
|
vtop -= nb_args + 1;
|
||||||
if (stack_adj + tempspace)
|
if (stack_adj + tempspace)
|
||||||
EI(0x13, 0, 2, 2, stack_adj + tempspace); // addi sp, sp, adj
|
EI(0x13, 0, 2, 2, stack_adj + tempspace); // addi sp, sp, adj
|
||||||
@ -725,9 +732,12 @@ ST_FUNC void gen_va_arg(CType *t)
|
|||||||
|
|
||||||
ST_FUNC void gen_fill_nops(int bytes)
|
ST_FUNC void gen_fill_nops(int bytes)
|
||||||
{
|
{
|
||||||
tcc_error("implement me: %s", __FUNCTION__);
|
|
||||||
if ((bytes & 3))
|
if ((bytes & 3))
|
||||||
tcc_error("alignment of code section not multiple of 4");
|
tcc_error("alignment of code section not multiple of 4");
|
||||||
|
while (bytes > 0) {
|
||||||
|
EI(0x13, 0, 0, 0, 0); // addi x0, x0, 0 == nop
|
||||||
|
bytes -= 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate forward branch to label:
|
// Generate forward branch to label:
|
||||||
@ -795,7 +805,6 @@ static void gen_opil(int op, int ll)
|
|||||||
d = ireg(d);
|
d = ireg(d);
|
||||||
ll = ll ? 0 : 8;
|
ll = ll ? 0 : 8;
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case TOK_PDIV:
|
|
||||||
default:
|
default:
|
||||||
tcc_error("implement me: %s(%s)", __FUNCTION__, get_tok_str(op, NULL));
|
tcc_error("implement me: %s(%s)", __FUNCTION__, get_tok_str(op, NULL));
|
||||||
|
|
||||||
@ -835,6 +844,7 @@ static void gen_opil(int op, int ll)
|
|||||||
case TOK_UMOD:
|
case TOK_UMOD:
|
||||||
o(0x33 | (d << 7) | (a << 15) | (b << 20) | (0x01 << 25) | (7 << 12)); //remu d, a, b
|
o(0x33 | (d << 7) | (a << 15) | (b << 20) | (0x01 << 25) | (7 << 12)); //remu d, a, b
|
||||||
break;
|
break;
|
||||||
|
case TOK_PDIV:
|
||||||
case TOK_UDIV:
|
case TOK_UDIV:
|
||||||
o(0x33 | (d << 7) | (a << 15) | (b << 20) | (0x01 << 25) | (5 << 12)); //divu d, a, b
|
o(0x33 | (d << 7) | (a << 15) | (b << 20) | (0x01 << 25) | (5 << 12)); //divu d, a, b
|
||||||
break;
|
break;
|
||||||
@ -887,6 +897,38 @@ ST_FUNC void gen_opl(int op)
|
|||||||
ST_FUNC void gen_opf(int op)
|
ST_FUNC void gen_opf(int op)
|
||||||
{
|
{
|
||||||
int rs1, rs2, rd, dbl, invert;
|
int rs1, rs2, rd, dbl, invert;
|
||||||
|
if (vtop[0].type.t == VT_LDOUBLE) {
|
||||||
|
CType type = vtop[0].type;
|
||||||
|
int func = 0;
|
||||||
|
int cond = -1;
|
||||||
|
switch (op) {
|
||||||
|
case '*': func = TOK___multf3; break;
|
||||||
|
case '+': func = TOK___addtf3; break;
|
||||||
|
case '-': func = TOK___subtf3; break;
|
||||||
|
case '/': func = TOK___divtf3; break;
|
||||||
|
case TOK_EQ: func = TOK___eqtf2; cond = 1; break;
|
||||||
|
case TOK_NE: func = TOK___netf2; cond = 0; break;
|
||||||
|
case TOK_LT: func = TOK___lttf2; cond = 10; break;
|
||||||
|
case TOK_GE: func = TOK___getf2; cond = 11; break;
|
||||||
|
case TOK_LE: func = TOK___letf2; cond = 12; break;
|
||||||
|
case TOK_GT: func = TOK___gttf2; cond = 13; break;
|
||||||
|
default: assert(0); break;
|
||||||
|
}
|
||||||
|
vpush_global_sym(&func_old_type, func);
|
||||||
|
vrott(3);
|
||||||
|
gfunc_call(2);
|
||||||
|
vpushi(0);
|
||||||
|
vtop->r = REG_IRET;
|
||||||
|
vtop->r2 = cond < 0 ? TREG_R(1) : VT_CONST;
|
||||||
|
if (cond < 0)
|
||||||
|
vtop->type = type;
|
||||||
|
else {
|
||||||
|
vpushi(0);
|
||||||
|
gen_opil(op, 1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
gv2(RC_FLOAT, RC_FLOAT);
|
gv2(RC_FLOAT, RC_FLOAT);
|
||||||
assert(vtop->type.t == VT_DOUBLE || vtop->type.t == VT_FLOAT);
|
assert(vtop->type.t == VT_DOUBLE || vtop->type.t == VT_FLOAT);
|
||||||
dbl = vtop->type.t == VT_DOUBLE;
|
dbl = vtop->type.t == VT_DOUBLE;
|
||||||
@ -953,12 +995,54 @@ ST_FUNC void gen_cvt_sxtw(void)
|
|||||||
|
|
||||||
ST_FUNC void gen_cvt_itof(int t)
|
ST_FUNC void gen_cvt_itof(int t)
|
||||||
{
|
{
|
||||||
tcc_error("implement me: %s", __FUNCTION__);
|
int rr = ireg(gv(RC_INT)), dr;
|
||||||
|
int u = vtop->type.t & VT_UNSIGNED;
|
||||||
|
int l = (vtop->type.t & VT_BTYPE) == VT_LLONG;
|
||||||
|
if (t == VT_LDOUBLE) {
|
||||||
|
int func = l ?
|
||||||
|
(u ? TOK___floatunditf : TOK___floatditf) :
|
||||||
|
(u ? TOK___floatunsitf : TOK___floatsitf);
|
||||||
|
vpush_global_sym(&func_old_type, func);
|
||||||
|
vrott(2);
|
||||||
|
gfunc_call(1);
|
||||||
|
vpushi(0);
|
||||||
|
vtop->type.t = t;
|
||||||
|
vtop->r = REG_IRET;
|
||||||
|
vtop->r2 = TREG_R(1);
|
||||||
|
} else {
|
||||||
|
vtop--;
|
||||||
|
dr = get_reg(RC_FLOAT);
|
||||||
|
vtop++;
|
||||||
|
vtop->r = dr;
|
||||||
|
dr = freg(dr);
|
||||||
|
EIu(0x53, 7, dr, rr, ((0x68 | (t == VT_DOUBLE ? 1 : 0)) << 5) | (u ? 1 : 0) | (l ? 2 : 0)); // fcvt.[sd].[wl][u]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC void gen_cvt_ftoi(int t)
|
ST_FUNC void gen_cvt_ftoi(int t)
|
||||||
{
|
{
|
||||||
tcc_error("implement me: %s", __FUNCTION__);
|
int ft = vtop->type.t & VT_BTYPE;
|
||||||
|
int l = (t & VT_BTYPE) == VT_LLONG;
|
||||||
|
int u = t & VT_UNSIGNED;
|
||||||
|
if (ft == VT_LDOUBLE) {
|
||||||
|
int func = l ?
|
||||||
|
(u ? TOK___fixunstfdi : TOK___fixtfdi) :
|
||||||
|
(u ? TOK___fixunstfsi : TOK___fixtfsi);
|
||||||
|
vpush_global_sym(&func_old_type, func);
|
||||||
|
vrott(2);
|
||||||
|
gfunc_call(1);
|
||||||
|
vpushi(0);
|
||||||
|
vtop->type.t = t;
|
||||||
|
vtop->r = REG_IRET;
|
||||||
|
} else {
|
||||||
|
int rr = freg(gv(RC_FLOAT)), dr;
|
||||||
|
vtop--;
|
||||||
|
dr = get_reg(RC_INT);
|
||||||
|
vtop++;
|
||||||
|
vtop->r = dr;
|
||||||
|
dr = ireg(dr);
|
||||||
|
EIu(0x53, 7, dr, rr, ((0x60 | (ft == VT_DOUBLE ? 1 : 0)) << 5) | (u ? 1 : 0) | (l ? 2 : 0)); // fcvt.[wl][u].[sd]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC void gen_cvt_ftof(int dt)
|
ST_FUNC void gen_cvt_ftof(int dt)
|
||||||
@ -995,7 +1079,8 @@ ST_FUNC void gen_cvt_ftof(int dt)
|
|||||||
|
|
||||||
ST_FUNC void ggoto(void)
|
ST_FUNC void ggoto(void)
|
||||||
{
|
{
|
||||||
tcc_error("implement me: %s", __FUNCTION__);
|
gcall_or_jmp(0);
|
||||||
|
vtop--;
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC void gen_vla_sp_save(int addr)
|
ST_FUNC void gen_vla_sp_save(int addr)
|
||||||
|
5
tccgen.c
5
tccgen.c
@ -2839,7 +2839,7 @@ static void gen_cast(CType *type)
|
|||||||
#if defined(TCC_TARGET_RISCV64)
|
#if defined(TCC_TARGET_RISCV64)
|
||||||
/* RISC-V keeps 32bit vals in registers sign-extended.
|
/* RISC-V keeps 32bit vals in registers sign-extended.
|
||||||
So here we need a zero-extension. */
|
So here we need a zero-extension. */
|
||||||
vtop->type.t = dbt;
|
vtop->type.t = VT_LLONG;
|
||||||
vpushi(32);
|
vpushi(32);
|
||||||
gen_op(TOK_SHL);
|
gen_op(TOK_SHL);
|
||||||
vpushi(32);
|
vpushi(32);
|
||||||
@ -5522,6 +5522,9 @@ special_math_val:
|
|||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
if ((ret.type.t & VT_BTYPE) == VT_QFLOAT)
|
if ((ret.type.t & VT_BTYPE) == VT_QFLOAT)
|
||||||
ret.r2 = REG_QRET;
|
ret.r2 = REG_QRET;
|
||||||
|
#elif defined TCC_TARGET_RISCV64
|
||||||
|
if ((ret.type.t & VT_BTYPE) == VT_LDOUBLE)
|
||||||
|
ret.r2 = ret.r + 1;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#ifndef TCC_TARGET_ARM64
|
#ifndef TCC_TARGET_ARM64
|
||||||
|
Loading…
Reference in New Issue
Block a user