mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-20 08:19:28 +00:00
Add inline assembler hacks for restoring the $gp register on the alpha,
Estimated hours taken: 24
Add inline assembler hacks for restoring the $gp register on the alpha,
to make the `asm_fast.gc' grade work on the alpha.
runtime/goto.h:
For the alpha, change the GOTO macro so that it sets up
register $27 (the "procedure value" register) to contain the
address to which you are going to jump, and change the
Define_{entry,local,static} macros so that they have a `ldgp'
instruction after the label which restores the gp register from
$27.
runtime/call.mod:
For the alpha, change the call macro so that it uses a `ldgp'
instruction to restore the gp register on return from a call.
Add new call_localret macro, for the case when the continuation
label is a local label (this is like the inverse of the localcall
macro), because a call_localret is two instructions cheaper
than the equivalent call would be.
runtime/engine.mod:
In call_engine(), we need to use `Define_label(engine_done)'
rather than just `engine_done:', so that it works on the alpha.
These changes improve the speed of the compiler by about 21%,
and cut executable size by about 24%.
There's still a fair bit of room for improving efficiency by
avoiding moves to $27 and `ldgp' instructions in situations
where they aren't needed.
This commit is contained in:
@@ -80,7 +80,7 @@ static void init_registers(void)
|
||||
/* The gcc-specific version */
|
||||
|
||||
void call_engine(Code *entry_point)
|
||||
{
|
||||
{{
|
||||
/*
|
||||
** Allocate some space for local variables in other
|
||||
** procedures. This used to be done by just calling
|
||||
@@ -134,7 +134,7 @@ void call_engine(Code *entry_point)
|
||||
|
||||
noprof_call(entry_point, LABEL(engine_done));
|
||||
|
||||
engine_done:
|
||||
Define_label(engine_done);
|
||||
/*
|
||||
** Save any registers which will get clobbered by the normal
|
||||
** C function call / return mechanism
|
||||
@@ -180,7 +180,7 @@ engine_done:
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}}
|
||||
|
||||
/* with nonlocal gotos, we don't save the previous locations */
|
||||
void dump_prev_locations(void) {}
|
||||
|
||||
113
runtime/goto.h
113
runtime/goto.h
@@ -35,6 +35,7 @@
|
||||
#define paste(a,b) a##b
|
||||
#define stringify(string) #string
|
||||
#define entry(label) paste(entry_,label)
|
||||
#define skip(label) paste(skip_,label)
|
||||
|
||||
#ifdef SPLIT_C_FILES
|
||||
#define MODULE_STATIC_OR_EXTERN extern
|
||||
@@ -42,6 +43,84 @@
|
||||
#define MODULE_STATIC_OR_EXTERN static
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/* MACHINE SPECIFIC STUFF REQUIRED FOR NON-LOCAL GOTOS */
|
||||
|
||||
#if defined(__alpha__)
|
||||
|
||||
/* when doing a jump, we need to set $27, the "procedure value" register,
|
||||
to the address we are jumping to, so that we can use an `ldgp'
|
||||
instruction in ASM_ENTRY to set up the right gp value.
|
||||
*/
|
||||
#define ASM_JUMP(address) \
|
||||
__asm__("bis %0, %0, $27\n\t" \
|
||||
: : "r"(address) : "$27"); \
|
||||
goto *(address)
|
||||
/* Explanation:
|
||||
Move `address' to register $27
|
||||
Jump to `address'
|
||||
*/
|
||||
|
||||
/* on entry to a procedure, we need to load the $gp register
|
||||
with the correct value relative to the current address in $27 */
|
||||
#define ASM_ENTRY(label) \
|
||||
/* on fall-thru, we need to skip the ldgp instruction */ \
|
||||
goto skip(label); \
|
||||
entry(label): \
|
||||
__asm__ __volatile__ ( \
|
||||
".globl entry_" stringify(label) "\n" \
|
||||
"entry_" stringify(label) ":\n\t" \
|
||||
"ldgp $gp, 0($27)" \
|
||||
: : : "memory" \
|
||||
); \
|
||||
skip(label):
|
||||
/* even static entry points must fix up the $gp register, since
|
||||
although there won't be any direct calls to them from another
|
||||
C file, their address may be taken and so there may be indirect
|
||||
calls */
|
||||
#define ASM_STATIC_ENTRY(label) \
|
||||
/* on fall-thru, we need to skip the ldgp instruction */ \
|
||||
goto skip(label); \
|
||||
entry(label): \
|
||||
__asm__ __volatile__ ( \
|
||||
"entry_" stringify(label) ":\n\t" \
|
||||
"ldgp $gp, 0($27)" \
|
||||
: : : "memory" \
|
||||
); \
|
||||
skip(label):
|
||||
/* even local entry points must fix up the $gp register, since
|
||||
although there won't be any direct calls to them from another
|
||||
C file, their address may be taken and so there may be indirect
|
||||
calls */
|
||||
#define ASM_LOCAL_ENTRY(label) \
|
||||
/* on fall-thru, we need to skip the ldgp instruction */ \
|
||||
goto skip(label); \
|
||||
entry(label): \
|
||||
__asm__ __volatile__ ( \
|
||||
"ldgp $gp, 0($27)" \
|
||||
: : : "memory" \
|
||||
); \
|
||||
skip(label):
|
||||
#else
|
||||
|
||||
#define ASM_JUMP(label) goto *(label)
|
||||
#define ASM_ENTRY(label) \
|
||||
entry(label): \
|
||||
__asm__(".globl entry_" stringify(label) "\n\t" \
|
||||
"entry_" stringify(label) ":" \
|
||||
);
|
||||
#define ASM_STATIC_ENTRY(label) \
|
||||
entry(label): \
|
||||
__asm__ ( \
|
||||
"entry_" stringify(label) ":" \
|
||||
);
|
||||
#define ASM_LOCAL_ENTRY(label) \
|
||||
entry(label): ;
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(USE_GCC_NONLOCAL_GOTOS)
|
||||
|
||||
#ifndef __GNUC__
|
||||
@@ -97,22 +176,24 @@
|
||||
/* body of module goes here */
|
||||
#define END_MODULE } }
|
||||
|
||||
|
||||
#if defined(USE_ASM_LABELS)
|
||||
#define Declare_entry(label) \
|
||||
extern void label(void) __asm__("entry_" stringify(label))
|
||||
#define Declare_static(label) \
|
||||
static void label(void) __asm__("entry_" stringify(label))
|
||||
#define Define_extern_entry(label) Declare_entry(label)
|
||||
#define Define_entry(label) \
|
||||
} \
|
||||
label: \
|
||||
__asm__(".globl entry_" stringify(label) "\n" \
|
||||
"entry_" stringify(label) ":"); \
|
||||
#define Define_entry(label) \
|
||||
ASM_ENTRY(label) \
|
||||
} \
|
||||
label: \
|
||||
PRETEND_ADDRESS_IS_USED(&&entry(label)); \
|
||||
{
|
||||
#define Define_static(label) \
|
||||
} \
|
||||
label: \
|
||||
__asm__("entry_" stringify(label) ":"); \
|
||||
ASM_STATIC_ENTRY(label) \
|
||||
} \
|
||||
label: \
|
||||
PRETEND_ADDRESS_IS_USED(&&entry(label)); \
|
||||
{
|
||||
/*
|
||||
The PRETEND_ADDRESS_IS_USED macro is necessary to
|
||||
@@ -125,6 +206,8 @@
|
||||
|
||||
#define ENTRY(label) (&label)
|
||||
|
||||
#define JUMP(label) ASM_JUMP(label)
|
||||
|
||||
#else
|
||||
/* !defined(USE_ASM_LABELS) */
|
||||
|
||||
@@ -144,24 +227,24 @@
|
||||
entry(label) = &&label
|
||||
#define ENTRY(label) (entry(label))
|
||||
|
||||
#define JUMP(label) goto (*label)
|
||||
|
||||
#endif
|
||||
|
||||
#define Declare_local(label) /* no declaration required */
|
||||
#define Define_local(label) \
|
||||
ASM_LOCAL_ENTRY(label) \
|
||||
} \
|
||||
label: \
|
||||
{
|
||||
#define init_local(label) make_local(stringify(label), &&label)
|
||||
#define Declare_label(label) /* no declaration required */
|
||||
#define Define_label(label) \
|
||||
} \
|
||||
label: \
|
||||
{
|
||||
#define Define_label(label) Define_local(label)
|
||||
#define init_label(label) make_label(stringify(label), &&label)
|
||||
|
||||
#define LOCAL(label) (&&label)
|
||||
#define LABEL(label) (&&label)
|
||||
#define GOTO(label) do { debuggoto(label); goto *(label); } while(0)
|
||||
#define LOCAL(label) (&&entry(label))
|
||||
#define LABEL(label) (&&entry(label))
|
||||
#define GOTO(label) do { debuggoto(label); JUMP(label); } while(0)
|
||||
#define GOTO_ENTRY(label) GOTO(ENTRY(label))
|
||||
#define GOTO_LOCAL(label) GOTO_LABEL(label)
|
||||
#define GOTO_LABEL(label) do { debuggoto(&&label); goto label; } while(0)
|
||||
|
||||
@@ -66,6 +66,37 @@ typedef void (*Cont) (void);
|
||||
GOTO_LABEL(label); \
|
||||
} while (0)
|
||||
|
||||
#if defined(__alpha__) && defined(USE_ASM_LABELS)
|
||||
#define noprof_call(proc, succ_cont) \
|
||||
({ \
|
||||
__label__ fixup_gp; \
|
||||
debugcall((proc), (succ_cont)); \
|
||||
succip = (&&fixup_gp); \
|
||||
set_prof_current_proc(proc); \
|
||||
GOTO(proc); \
|
||||
fixup_gp: \
|
||||
__asm__ __volatile__ ( \
|
||||
"ldgp $gp, 0($27)" \
|
||||
: : : "memory" \
|
||||
); \
|
||||
GOTO(succ_cont); \
|
||||
})
|
||||
/* same as above, but with GOTO_LABEL rather than GOTO */
|
||||
#define noprof_call_localret(proc, succ_cont) \
|
||||
({ \
|
||||
__label__ fixup_gp; \
|
||||
debugcall((proc), (succ_cont)); \
|
||||
succip = (&&fixup_gp); \
|
||||
set_prof_current_proc(proc); \
|
||||
GOTO(proc); \
|
||||
fixup_gp: \
|
||||
__asm__ __volatile__ ( \
|
||||
"ldgp $gp, 0($27)" \
|
||||
: : : "memory" \
|
||||
); \
|
||||
GOTO_LABEL(succ_cont); \
|
||||
})
|
||||
#else
|
||||
#define noprof_call(proc, succ_cont) \
|
||||
do { \
|
||||
debugcall((proc), (succ_cont)); \
|
||||
@@ -73,6 +104,9 @@ typedef void (*Cont) (void);
|
||||
set_prof_current_proc(proc); \
|
||||
GOTO(proc); \
|
||||
} while (0)
|
||||
#define noprof_call_localret(proc, succ_cont) \
|
||||
noprof_call((proc), LABEL(succ_cont))
|
||||
#endif
|
||||
|
||||
#define localcall(label, succ_cont, current_label) \
|
||||
do { \
|
||||
@@ -85,11 +119,14 @@ typedef void (*Cont) (void);
|
||||
|
||||
#define call(proc, succ_cont, current_label) \
|
||||
do { \
|
||||
debugcall((proc), (succ_cont)); \
|
||||
succip = (succ_cont); \
|
||||
PROFILE((proc), (current_label)); \
|
||||
set_prof_current_proc(proc); \
|
||||
GOTO(proc); \
|
||||
noprof_call((proc), (succ_cont)); \
|
||||
} while (0)
|
||||
|
||||
#define call_localret(proc, succ_cont, current_label) \
|
||||
do { \
|
||||
PROFILE((proc), (current_label)); \
|
||||
noprof_call_localret(proc, succ_cont); \
|
||||
} while (0)
|
||||
|
||||
#define call_det_closure(succ_cont, current_label) \
|
||||
|
||||
Reference in New Issue
Block a user