riscv: Merge stack code, fix interrupted code

- Stack pointer is kept below register save area. This ensures that
registers are not overwritten by interrupt handlers.
- RV32 and 64 code is merged to base class.
This commit is contained in:
Jeppe 2022-07-02 14:08:31 +02:00
parent 37b5147b19
commit f5cf8956c5
3 changed files with 200 additions and 338 deletions

View File

@ -60,7 +60,10 @@ unit cgrv;
procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
procedure a_jmp_name(list : TAsmList;const s : string); override;
procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
procedure g_save_registers(list: TAsmList); override;
procedure g_restore_registers(list: TAsmList); override;
@ -500,6 +503,202 @@ unit cgrv;
end;
procedure tcgrv.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
const
{$ifdef cpu64bitalu}
store_int_op = A_SD;
{$else cpu64bitalu}
store_int_op = A_SW;
{$endif cpu64bitalu}
var
regs, fregs: tcpuregisterset;
r: TSuperRegister;
href: treference;
stackcount, stackAdjust: longint;
begin
if not(nostackframe) then
begin
a_reg_alloc(list,NR_STACK_POINTER_REG);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
a_reg_alloc(list,NR_FRAME_POINTER_REG);
{ Int registers }
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
if (pi_do_call in current_procinfo.flags) then
regs:=regs+[RS_RETURN_ADDRESS_REG];
stackcount:=0;
for r:=RS_X0 to RS_X31 do
if r in regs then
inc(stackcount,sizeof(pint));
{ Float registers }
fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
for r:=RS_F0 to RS_F31 do
if r in fregs then
inc(stackcount,8);
inc(localsize,stackcount);
if not is_imm12(-localsize) then
begin
if not (RS_RETURN_ADDRESS_REG in regs) then
begin
include(regs,RS_RETURN_ADDRESS_REG);
inc(localsize,sizeof(pint));
end;
end;
reference_reset_base(href,NR_STACK_POINTER_REG,stackcount,ctempposinvalid,0,[]);
stackAdjust:=0;
if stackcount>0 then
begin
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-stackcount));
stackAdjust:=stackcount;
dec(localsize,stackcount);
end;
for r:=RS_X0 to RS_X31 do
if r in regs then
begin
dec(href.offset,sizeof(pint));
list.concat(taicpu.op_reg_ref(store_int_op,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
end;
{ Float registers }
for r:=RS_F0 to RS_F31 do
if r in fregs then
begin
dec(href.offset,8);
list.concat(taicpu.op_reg_ref(A_FSD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
end;
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,stackAdjust));
if localsize>0 then
begin
localsize:=align(localsize,sizeof(pint));
if is_imm12(-localsize) then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize))
else
begin
a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
end;
end;
end;
end;
procedure tcgrv.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
const
{$ifdef cpu64bitalu}
load_op = A_LD;
{$else cpu64bitalu}
load_op = A_LW;
{$endif cpu64bitalu}
var
r: tsuperregister;
regs, fregs: tcpuregisterset;
stacksize, localsize, precompensation, postcompensation: longint;
href: treference;
begin
if not(nostackframe) then
begin
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
if (pi_do_call in current_procinfo.flags) then
regs:=regs+[RS_RETURN_ADDRESS_REG];
stacksize:=0;
for r:=RS_X31 downto RS_X0 do
if r in regs then
inc(stacksize,sizeof(pint));
{ Float registers }
fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
for r:=RS_F0 to RS_F31 do
if r in fregs then
inc(stacksize,8);
localsize:=current_procinfo.calc_stackframe_size+stacksize;
if localsize>0 then
begin
localsize:=align(localsize,sizeof(pint));
if not is_imm12(-localsize) then
begin
if not (RS_RETURN_ADDRESS_REG in regs) then
begin
include(regs,RS_RETURN_ADDRESS_REG);
inc(localsize,sizeof(pint));
inc(stacksize,sizeof(pint));
end;
end;
end;
if not is_imm12(localsize) then
begin
precompensation:=localsize-2032;
postcompensation:=localsize-precompensation;
end
else
begin
precompensation:=0;
postcompensation:=localsize;
end;
reference_reset_base(href,NR_STACK_POINTER_REG,postcompensation-stacksize,ctempposinvalid,0,[]);
if precompensation>0 then
begin
if is_imm12(precompensation) then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,precompensation))
else
begin
{ use X12 as temporary register as it is not callee-saved }
a_load_const_reg(list,OS_INT,precompensation,NR_X12);
list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_X12));
end;
end;
{ Float registers }
for r:=RS_F31 downto RS_F0 do
if r in fregs then
begin
list.concat(taicpu.op_reg_ref(A_FLD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
inc(href.offset,8);
end;
for r:=RS_X31 downto RS_X0 do
if r in regs then
begin
list.concat(taicpu.op_reg_ref(load_op,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
inc(href.offset,sizeof(pint));
end;
if postcompensation>0 then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,postcompensation));
end;
if po_interrupt in current_procinfo.procdef.procoptions then
begin
list.concat(Taicpu.Op_none(A_MRET));
end
else
list.concat(taicpu.op_reg_reg(A_JALR,NR_X0,NR_RETURN_ADDRESS_REG));
end;
procedure tcgrv.g_save_registers(list: TAsmList);
begin
end;

View File

@ -43,9 +43,6 @@ unit cgcpu;
{ 32x32 to 64 bit multiplication }
procedure a_mul_reg_reg_pair(list: TAsmList;size: tcgsize; src1,src2,dstlo,dsthi: tregister); override;
procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
@ -165,171 +162,6 @@ unit cgcpu;
end;
procedure tcgrv32.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
var
regs, fregs: tcpuregisterset;
r: TSuperRegister;
href: treference;
stackcount, stackAdjust: longint;
begin
if not(nostackframe) then
begin
a_reg_alloc(list,NR_STACK_POINTER_REG);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
a_reg_alloc(list,NR_FRAME_POINTER_REG);
reference_reset_base(href,NR_STACK_POINTER_REG,-4,ctempposinvalid,0,[]);
{ Int registers }
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
if (pi_do_call in current_procinfo.flags) then
regs:=regs+[RS_RETURN_ADDRESS_REG];
stackcount:=0;
for r:=RS_X0 to RS_X31 do
if r in regs then
inc(stackcount,4);
{ Float registers }
fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
for r:=RS_F0 to RS_F31 do
if r in fregs then
inc(stackcount,8);
inc(localsize,stackcount);
if not is_imm12(-localsize) then
begin
if not (RS_RETURN_ADDRESS_REG in regs) then
begin
include(regs,RS_RETURN_ADDRESS_REG);
inc(localsize,4);
end;
end;
stackAdjust:=0;
if (CPURV_HAS_COMPACT in cpu_capabilities[current_settings.cputype]) and
(stackcount>0) then
begin
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-stackcount));
inc(href.offset,stackcount);
stackAdjust:=stackcount;
dec(localsize,stackcount);
end;
for r:=RS_X0 to RS_X31 do
if r in regs then
begin
list.concat(taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
dec(href.offset,4);
end;
{ Float registers }
for r:=RS_F0 to RS_F31 do
if r in fregs then
begin
list.concat(taicpu.op_reg_ref(A_FSD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
dec(href.offset,8);
end;
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,stackAdjust));
if localsize>0 then
begin
localsize:=align(localsize,4);
if is_imm12(-localsize) then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize))
else
begin
a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
end;
end;
end;
end;
procedure tcgrv32.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
var
r: tsuperregister;
regs, fregs: tcpuregisterset;
localsize: longint;
href: treference;
begin
if not(nostackframe) then
begin
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
if (pi_do_call in current_procinfo.flags) then
regs:=regs+[RS_RETURN_ADDRESS_REG];
reference_reset_base(href,NR_STACK_POINTER_REG,-4,ctempposinvalid,0,[]);
for r:=RS_X31 downto RS_X0 do
if r in regs then
dec(href.offset,4);
{ Float registers }
fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
for r:=RS_F0 to RS_F31 do
if r in fregs then
dec(href.offset,8);
localsize:=current_procinfo.calc_stackframe_size+(-href.offset-4);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG,0))
else if localsize>0 then
begin
localsize:=align(localsize,4);
if is_imm12(localsize) then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
else
begin
if not (RS_RETURN_ADDRESS_REG in regs) then
begin
include(regs,RS_RETURN_ADDRESS_REG);
dec(href.offset,4);
inc(localsize,4);
end;
a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
end;
end;
{ Float registers }
for r:=RS_F31 downto RS_F0 do
if r in fregs then
begin
inc(href.offset,8);
list.concat(taicpu.op_reg_ref(A_FLD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
end;
for r:=RS_X31 downto RS_X0 do
if r in regs then
begin
inc(href.offset,4);
list.concat(taicpu.op_reg_ref(A_LW,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
end;
end;
if po_interrupt in current_procinfo.procdef.procoptions then
begin
list.concat(Taicpu.Op_none(A_MRET));
end
else
list.concat(taicpu.op_reg_reg(A_JALR,NR_X0,NR_RETURN_ADDRESS_REG));
end;
procedure tcgrv32.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
var
paraloc1, paraloc2, paraloc3: TCGPara;

View File

@ -46,9 +46,6 @@ unit cgcpu;
procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
procedure g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean); override;
procedure g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean); override;
procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
procedure g_concatcopy(list: TAsmList; const source, dest: treference; len: aint); override;
end;
@ -356,172 +353,6 @@ implementation
end;
procedure tcgrv64.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
var
regs, fregs: tcpuregisterset;
r: TSuperRegister;
href: treference;
stackcount, stackAdjust: longint;
begin
if not(nostackframe) then
begin
a_reg_alloc(list,NR_STACK_POINTER_REG);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
a_reg_alloc(list,NR_FRAME_POINTER_REG);
reference_reset_base(href,NR_STACK_POINTER_REG,-8,ctempposinvalid,0,[]);
{ Int registers }
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
if (pi_do_call in current_procinfo.flags) then
regs:=regs+[RS_RETURN_ADDRESS_REG];
stackcount:=0;
for r:=RS_X0 to RS_X31 do
if r in regs then
inc(stackcount,8);
{ Float registers }
fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
for r:=RS_F0 to RS_F31 do
if r in fregs then
inc(stackcount,8);
inc(localsize,stackcount);
if not is_imm12(-(localsize-stackcount)) then
begin
if not (RS_RETURN_ADDRESS_REG in regs) then
begin
include(regs,RS_RETURN_ADDRESS_REG);
inc(localsize,8);
inc(stackcount,8);
end;
end;
stackAdjust:=0;
if (CPURV_HAS_COMPACT in cpu_capabilities[current_settings.cputype]) and
(stackcount>0) then
begin
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-stackcount));
inc(href.offset,stackcount);
stackAdjust:=stackcount;
dec(localsize,stackcount);
end;
for r:=RS_X0 to RS_X31 do
if r in regs then
begin
list.concat(taicpu.op_reg_ref(A_SD,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
dec(href.offset,8);
end;
{ Float registers }
for r:=RS_F0 to RS_F31 do
if r in fregs then
begin
list.concat(taicpu.op_reg_ref(A_FSD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
dec(href.offset,8);
end;
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,stackAdjust));
if localsize>0 then
begin
localsize:=align(localsize,8);
if is_imm12(-localsize) then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize))
else
begin
a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
end;
end;
end;
end;
procedure tcgrv64.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
var
r: tsuperregister;
regs, fregs: tcpuregisterset;
localsize: longint;
href: treference;
begin
if not(nostackframe) then
begin
regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
if (pi_do_call in current_procinfo.flags) then
regs:=regs+[RS_RETURN_ADDRESS_REG];
reference_reset_base(href,NR_STACK_POINTER_REG,-8,ctempposinvalid,0,[]);
for r:=RS_X31 downto RS_X0 do
if r in regs then
dec(href.offset,8);
{ Float registers }
fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
for r:=RS_F0 to RS_F31 do
if r in fregs then
dec(href.offset,8);
localsize:=current_procinfo.calc_stackframe_size+(-href.offset-8);
if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG,0))
else if localsize>0 then
begin
localsize:=align(localsize,8);
if is_imm12(localsize) then
list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
else
begin
if not (RS_RETURN_ADDRESS_REG in regs) then
begin
include(regs,RS_RETURN_ADDRESS_REG);
dec(href.offset,8);
inc(localsize,8);
end;
a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
end;
end;
{ Float registers }
for r:=RS_F31 downto RS_F0 do
if r in fregs then
begin
inc(href.offset,8);
list.concat(taicpu.op_reg_ref(A_FLD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
end;
for r:=RS_X31 downto RS_X0 do
if r in regs then
begin
inc(href.offset,8);
list.concat(taicpu.op_reg_ref(A_LD,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
end;
end;
if po_interrupt in current_procinfo.procdef.procoptions then
begin
list.concat(Taicpu.Op_none(A_MRET));
end
else
list.concat(taicpu.op_reg_reg(A_JALR,NR_X0,NR_RETURN_ADDRESS_REG));
end;
procedure tcgrv64.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
var
paraloc1, paraloc2, paraloc3: TCGPara;