From: Matt Birkholz Date: Tue, 25 Nov 2014 12:28:27 +0000 (-0700) Subject: smp: Add i386 assembly to allocate/access thread-local variables. X-Git-Url: https://birchwood-abbey.net/git?a=commitdiff_plain;h=2fdfa7774d6943e197a45f5b2a3d1ff00a31472d;p=mit-scheme.git smp: Add i386 assembly to allocate/access thread-local variables. Change the storage class of thread-local variables in use thus far. --- diff --git a/src/microcode/cmpauxmd/i386.m4 b/src/microcode/cmpauxmd/i386.m4 index bf538d6d3..ee3534a76 100644 --- a/src/microcode/cmpauxmd/i386.m4 +++ b/src/microcode/cmpauxmd/i386.m4 @@ -41,7 +41,7 @@ ### 2) The C compiler divides registers into three groups: ### - Linkage registers, used for procedure calls and global ### references. On i386 (gcc and Zortech C): %ebp, %esp. -### - super temporaries, not preserved accross procedure calls and +### - super temporaries, not preserved across procedure calls and ### always usable. On i386 (gcc and Zortech C): %eax, %edx, %ecx. ### - preserved registers saved by the callee if they are written. ### On i386 (gcc and Zortech C): all others (%ebx, %esi, %edi). @@ -176,6 +176,9 @@ IFNDASM(`define(popfd,`popf')') ifdef(`SUPPRESS_LEADING_UNDERSCORE', `define(EVR,`$1')', `define(EVR,`_$1')') +ifdef(`ENABLE_SMP', + `define(TLVR,`%gs:$1\@ntpoff')', + `define(TLVR,`EVR($1)')') # When using the Watcom C compiler with register-based calling # conventions, source-code function names normally expand to `FOO_', @@ -350,6 +353,38 @@ define(rmask,REG(ebp)) IFDASM(`.586p .model flat') +use_external_data(EVR(utility_table)) + +ifdef(`ENABLE_SMP',` + .section .tbss,"awT",\@nobits + .align 4 +define(`define_tllong',` + .globl $1 + .type $1 STT_TLS + .size $1, 4 +$1: + .zero 4 +') + define_tllong(Free) + define_tllong(heap_alloc_limit) + define_tllong(heap_end) + define_tllong(stack_guard) + define_tllong(stack_pointer) + define_tllong(stack_start) + define_tllong(C_Stack_Pointer) + define_tllong(C_Frame_Pointer) + + .zero 128 + .globl Registers + .type Registers STT_TLS + .size Registers, eval(REGBLOCK_SIZE_IN_OBJECTS*4) +Registers: + .zero eval(REGBLOCK_SIZE_IN_OBJECTS*4) +',` +ifdef(`WIN32',` +use_external_data(EVR(RegistersPtr)) +',` + DECLARE_DATA_SEGMENT() declare_alignment(2) @@ -359,29 +394,25 @@ use_external_data(EVR(heap_end)) use_external_data(EVR(stack_guard)) use_external_data(EVR(stack_pointer)) use_external_data(EVR(stack_start)) -use_external_data(EVR(utility_table)) -ifdef(`WIN32',` -use_external_data(EVR(RegistersPtr)) -',` define_data(Regstart) allocate_space(Regstart,128) define_data(Registers) allocate_space(Registers,eval(REGBLOCK_SIZE_IN_OBJECTS*4)) -') - -define_data(i387_presence) -allocate_longword(i387_presence) - -define_data(sse_presence) -allocate_longword(sse_presence) define_data(C_Stack_Pointer) allocate_longword(C_Stack_Pointer) define_data(C_Frame_Pointer) allocate_longword(C_Frame_Pointer) +')') + +define_data(i387_presence) +allocate_longword(i387_presence) + +define_data(sse_presence) +allocate_longword(sse_presence) define_data(ia32_cpuid_supported) allocate_longword(ia32_cpuid_supported) @@ -559,7 +590,7 @@ no_cpuid_instr: # set esp to something funny. define_c_label(within_c_stack) - OP(mov,l) TW(EVR(C_Stack_Pointer),REG(eax)) + OP(mov,l) TW(TLVR(C_Stack_Pointer),REG(eax)) # Are we currently in C, signalled by having no saved C stack pointer? OP(cmp,l) TW(IMM(0),REG(eax)) # Yes: just call the function without messing with esp. @@ -568,7 +599,7 @@ define_c_label(within_c_stack) OP(push,l) REG(ebp) # Save frame pointer OP(mov,l) TW(REG(esp),REG(ebp)) OP(mov,l) TW(REG(eax),REG(esp)) # Switch to C stack - OP(mov,l) TW(IMM(0),EVR(C_Stack_Pointer)) + OP(mov,l) TW(IMM(0),TLVR(C_Stack_Pointer)) OP(push,l) IMM(0) # Align sp to 16 bytes OP(push,l) REG(ebp) # Save stack pointer OP(push,l) LOF(HEX(c),REG(ebp)) # Push argument @@ -578,7 +609,7 @@ define_debugging_label(within_c_stack_restore) OP(pop,l) REG(eax) # Pop argument OP(mov,l) TW(REG(esp),REG(eax)) # Restore C stack ptr OP(add,l) TW(IMM(8),REG(eax)) - OP(mov,l) TW(REG(eax),EVR(C_Stack_Pointer)) + OP(mov,l) TW(REG(eax),TLVR(C_Stack_Pointer)) OP(pop,l) REG(esp) # Restore stack pointer # and switch back to # Scheme stack @@ -603,15 +634,18 @@ define_c_label(C_to_interface) OP(push,l) REG(ebx) OP(mov,l) TW(LOF(8,REG(ebp)),REG(edx)) # Entry point # Preserve frame ptr - OP(mov,l) TW(REG(ebp),EVR(C_Frame_Pointer)) + OP(mov,l) TW(REG(ebp),TLVR(C_Frame_Pointer)) # Preserve stack ptr - OP(mov,l) TW(REG(esp),EVR(C_Stack_Pointer)) + OP(mov,l) TW(REG(esp),TLVR(C_Stack_Pointer)) # Register block = %esi # Scheme offset in NT ifdef(`WIN32', ` OP(mov,l) TW(ABS(EVR(RegistersPtr)),regs)', -` OP(lea,l) TW(ABS(EVR(Registers)),regs)') +`ifdef(`ENABLE_SMP', +` OP(mov,l) TW(%gs:0,regs) + OP(add,l) TW($Registers\@ntpoff,regs)', +` OP(lea,l) TW(ABS(EVR(Registers)),regs)')') jmp EPFR(interface_to_scheme) define_hook_label(trampoline_to_interface) @@ -630,8 +664,8 @@ define_debugging_label(scheme_to_interface) # These two moves must happen _before_ the ffree instructions below. # Otherwise recovery from SIGFPE there will fail. - OP(mov,l) TW(REG(esp),EVR(stack_pointer)) - OP(mov,l) TW(rfree,EVR(Free)) + OP(mov,l) TW(REG(esp),TLVR(stack_pointer)) + OP(mov,l) TW(rfree,TLVR(Free)) IF387(` OP(cmp,l) TW(IMM(0),ABS(EVR(i387_presence))) @@ -647,11 +681,11 @@ IF387(` scheme_to_interface_proceed: ') - OP(mov,l) TW(EVR(C_Stack_Pointer),REG(esp)) - OP(mov,l) TW(EVR(C_Frame_Pointer),REG(ebp)) + OP(mov,l) TW(TLVR(C_Stack_Pointer),REG(esp)) + OP(mov,l) TW(TLVR(C_Frame_Pointer),REG(ebp)) # Signal to within_c_stack that we are now in C land. - OP(mov,l) TW(IMM(0),EVR(C_Stack_Pointer)) + OP(mov,l) TW(IMM(0),TLVR(C_Stack_Pointer)) OP(sub,l) TW(IMM(8),REG(esp)) # alloc struct return @@ -689,14 +723,14 @@ IF387(` ffree ST(7) interface_to_scheme_proceed: ') - OP(mov,l) TW(EVR(Free),rfree) # Free pointer = %edi + OP(mov,l) TW(TLVR(Free),rfree) # Free pointer = %edi OP(mov,l) TW(LOF(REGBLOCK_VAL(),regs),REG(eax)) # Value/dynamic link OP(mov,l) TW(IMM(ADDRESS_MASK),rmask) # = %ebp # Restore the C stack pointer, which we zeroed back in # scheme_to_interface, for within_c_stack. - OP(mov,l) TW(REG(esp),EVR(C_Stack_Pointer)) - OP(mov,l) TW(EVR(stack_pointer),REG(esp)) + OP(mov,l) TW(REG(esp),TLVR(C_Stack_Pointer)) + OP(mov,l) TW(TLVR(stack_pointer),REG(esp)) OP(mov,l) TW(REG(eax),REG(ecx)) # Preserve if used OP(and,l) TW(rmask,REG(ecx)) # Restore potential dynamic link OP(mov,l) TW(REG(ecx),LOF(REGBLOCK_DLINK(),regs)) @@ -889,13 +923,13 @@ set_interrupt_enables_memtop_1: # If GC is enabled, set memtop to the heap allocation limit. OP(test,l) TW(IMM(INT_GC),REG(ecx)) jz set_interrupt_enables_memtop_2 - OP(mov,l) TW(ABS(EVR(heap_alloc_limit)),REG(edx)) + OP(mov,l) TW(ABS(TLVR(heap_alloc_limit)),REG(edx)) jmp set_interrupt_enables_set_memtop set_interrupt_enables_memtop_2: # Otherwise, there is no interrupt pending, and GC is not # enabled, so set memtop to the absolute heap end. - OP(mov,l) TW(ABS(EVR(heap_end)),REG(edx)) + OP(mov,l) TW(ABS(TLVR(heap_end)),REG(edx)) set_interrupt_enables_set_memtop: OP(mov,l) TW(REG(edx),LOF(REGBLOCK_MEMTOP(),regs)) @@ -903,11 +937,11 @@ set_interrupt_enables_set_memtop: set_interrupt_enables_determine_stack_guard: OP(test,l) TW(IMM(INT_Stack_Overflow),REG(ecx)) jz set_interrupt_enables_stack_guard_1 - OP(mov,l) TW(ABS(EVR(stack_guard)),REG(edx)) + OP(mov,l) TW(ABS(TLVR(stack_guard)),REG(edx)) jmp set_interrupt_enables_set_stack_guard set_interrupt_enables_stack_guard_1: - OP(mov,l) TW(ABS(EVR(stack_start)),REG(edx)) + OP(mov,l) TW(ABS(TLVR(stack_start)),REG(edx)) set_interrupt_enables_set_stack_guard: OP(mov,l) TW(REG(edx),LOF(REGBLOCK_STACK_GUARD(),regs)) diff --git a/src/microcode/cmpint.c b/src/microcode/cmpint.c index 5774d1b22..f62662c63 100644 --- a/src/microcode/cmpint.c +++ b/src/microcode/cmpint.c @@ -251,7 +251,11 @@ long C_return_value; + COMPILER_REGBLOCK_EXTRA_SIZE) #ifndef REGBLOCK_ALLOCATED_BY_INTERFACE - SCHEME_OBJECT Registers [REGBLOCK_LENGTH]; + __thread SCHEME_OBJECT Registers [REGBLOCK_LENGTH]; +# ifdef ENABLE_SMP + __thread void *C_Stack_Pointer; + __thread void *C_Frame_Pointer; +# endif #endif #ifndef ASM_RESET_HOOK diff --git a/src/microcode/extern.h b/src/microcode/extern.h index 515abce7a..4b1435865 100644 --- a/src/microcode/extern.h +++ b/src/microcode/extern.h @@ -37,7 +37,7 @@ USA. extern SCHEME_OBJECT * RegistersPtr; # define Registers RegistersPtr #else - extern SCHEME_OBJECT Registers []; + extern __thread SCHEME_OBJECT Registers []; #endif #define GET_REG_O(i) (Registers[REGBLOCK_##i]) @@ -138,11 +138,11 @@ extern void set_ulong_register (unsigned int, unsigned long); # define Bignum_Debug 0 #endif -extern SCHEME_OBJECT * Free; -extern SCHEME_OBJECT * Free_primitive; -extern SCHEME_OBJECT * heap_alloc_limit; -extern SCHEME_OBJECT * heap_start; -extern SCHEME_OBJECT * heap_end; +extern __thread SCHEME_OBJECT * Free; +extern __thread SCHEME_OBJECT * Free_primitive; +extern __thread SCHEME_OBJECT * heap_alloc_limit; +extern __thread SCHEME_OBJECT * heap_start; +extern __thread SCHEME_OBJECT * heap_end; #ifdef ENABLE_SMP extern SCHEME_OBJECT * p0_heap_start; extern SCHEME_OBJECT * shared_heap_start; @@ -150,10 +150,10 @@ extern SCHEME_OBJECT * shared_heap_free; extern SCHEME_OBJECT * shared_heap_end; #endif -extern SCHEME_OBJECT * stack_pointer; -extern SCHEME_OBJECT * stack_guard; -extern SCHEME_OBJECT * stack_start; -extern SCHEME_OBJECT * stack_end; +extern __thread SCHEME_OBJECT * stack_pointer; +extern __thread SCHEME_OBJECT * stack_guard; +extern __thread SCHEME_OBJECT * stack_start; +extern __thread SCHEME_OBJECT * stack_end; extern SCHEME_OBJECT * constant_alloc_next; extern SCHEME_OBJECT * constant_start; @@ -161,7 +161,7 @@ extern SCHEME_OBJECT * constant_end; /* Address of the most recent return code in the stack. This is only meaningful while in compiled code. */ -extern SCHEME_OBJECT * last_return_code; +extern __thread SCHEME_OBJECT * last_return_code; extern SCHEME_OBJECT fixed_objects; extern SCHEME_OBJECT ephemeron_array; @@ -182,7 +182,7 @@ extern const char * Term_Names []; extern const char * term_messages []; extern const char * fixed_objects_names []; -extern bool trapping; +extern __thread bool trapping; extern const char * scheme_program_name; extern const char * OS_Name; @@ -196,9 +196,9 @@ extern SCHEME_OBJECT * memory_block_end; extern unsigned long heap_reserved; /* Amount of space needed when GC requested */ -extern unsigned long gc_space_needed; +extern __thread unsigned long gc_space_needed; #ifdef ENABLE_SMP -extern unsigned long gc_shared_space_needed; +extern __thread unsigned long gc_shared_space_needed; #endif /* Number of new ephemerons requested from the GC. */ diff --git a/src/microcode/history.h b/src/microcode/history.h index e9b450a6e..eead18509 100644 --- a/src/microcode/history.h +++ b/src/microcode/history.h @@ -75,8 +75,8 @@ USA. # define COMPILER_END_SUBPROBLEM() do {} while (false) #endif -extern SCHEME_OBJECT * history_register; -extern unsigned long prev_restore_history_offset; +extern __thread SCHEME_OBJECT * history_register; +extern __thread unsigned long prev_restore_history_offset; extern void reset_history (void); extern SCHEME_OBJECT * make_dummy_history (void); diff --git a/src/microcode/makegen/m4.sh b/src/microcode/makegen/m4.sh index 7e92f218e..be1ac2855 100755 --- a/src/microcode/makegen/m4.sh +++ b/src/microcode/makegen/m4.sh @@ -52,7 +52,8 @@ touch "${TMP_FILE}" if [ $# = 0 ] then - sed -e '/^#/D' | run_m4 | sed -e 's/@/$/g' -e 's/^ $//' + sed -e '/^#/D' | run_m4 \ + | sed -e 's/\([^\]\)@/\1$/g' -e 's/\\@/@/g' -e 's/^ $//' else SEEN_INPUT=0 while [ $# != 0 ]; do @@ -68,7 +69,8 @@ else if [ ${SEEN_INPUT} -eq 0 ]; then sed -e '/^#/D' >> "${TMP_FILE}" fi - run_m4 < "${TMP_FILE}" | sed -e 's/@/$/g' -e 's/^ $//' + run_m4 < "${TMP_FILE}" \ + | sed -e 's/\([^\]\)@/\1$/g' -e 's/\\@/@/g' -e 's/^ $//' fi # If m4 was successful, run_m4 has deleted the temporary file. If diff --git a/src/microcode/storage.c b/src/microcode/storage.c index 246413973..e1d453888 100644 --- a/src/microcode/storage.c +++ b/src/microcode/storage.c @@ -33,13 +33,17 @@ USA. #endif /* next free word in heap */ +#ifndef ENABLE_SMP SCHEME_OBJECT * Free; +#endif /* value of Free on entry to primitive, or 0 if not in primitive */ -SCHEME_OBJECT * Free_primitive = 0; +__thread SCHEME_OBJECT * Free_primitive = 0; /* strict limit for Free */ +#ifndef ENABLE_SMP SCHEME_OBJECT * heap_alloc_limit; +#endif #ifdef ENABLE_SMP /* the start of From space */ @@ -54,18 +58,26 @@ SCHEME_OBJECT * shared_heap_free; #endif /* limits of local heap */ -SCHEME_OBJECT * heap_start; +__thread SCHEME_OBJECT * heap_start; +#ifndef ENABLE_SMP SCHEME_OBJECT * heap_end; +#endif /* pointer to most-recently pushed item */ +#ifndef ENABLE_SMP SCHEME_OBJECT * stack_pointer; +#endif /*-strict limit for stack_pointer */ +#ifndef ENABLE_SMP SCHEME_OBJECT * stack_guard; +#endif /* limits of stack */ +#ifndef ENABLE_SMP SCHEME_OBJECT * stack_start; -SCHEME_OBJECT * stack_end; +#endif +__thread SCHEME_OBJECT * stack_end; /* next free word in constant space */ SCHEME_OBJECT * constant_alloc_next; @@ -76,7 +88,7 @@ SCHEME_OBJECT * constant_end; /* Address of the most recent return code in the stack. This is only meaningful while in compiled code. */ -SCHEME_OBJECT * last_return_code; +__thread SCHEME_OBJECT * last_return_code; SCHEME_OBJECT fixed_objects; @@ -87,7 +99,7 @@ SCHEME_OBJECT fixed_objects; SCHEME_OBJECT ephemeron_array = SHARP_F; unsigned long ephemeron_count = 0; -bool trapping; +__thread bool trapping; SCHEME_OBJECT * memory_block_start; SCHEME_OBJECT * memory_block_end; @@ -95,9 +107,9 @@ SCHEME_OBJECT * memory_block_end; unsigned long heap_reserved; /* Amount of space needed when GC requested */ -unsigned long gc_space_needed; +__thread unsigned long gc_space_needed; #ifdef ENABLE_SMP -unsigned long gc_shared_space_needed; +__thread unsigned long gc_shared_space_needed; #endif /* Number of new ephemerons requested from the GC. */ diff --git a/src/microcode/utils.c b/src/microcode/utils.c index 2ed5d4bf1..b6ad533f0 100644 --- a/src/microcode/utils.c +++ b/src/microcode/utils.c @@ -35,8 +35,8 @@ USA. extern void OS2_handle_attention_interrupt (void); #endif -SCHEME_OBJECT * history_register; -unsigned long prev_restore_history_offset; +__thread SCHEME_OBJECT * history_register; +__thread unsigned long prev_restore_history_offset; static SCHEME_OBJECT copy_history (SCHEME_OBJECT); static void error_death (long, const char *) NORETURN; @@ -993,8 +993,8 @@ C_call_scheme (SCHEME_OBJECT proc, SCHEME_OBJECT * callers_last_return_code; #ifdef CC_IS_NATIVE - extern void * C_Frame_Pointer; - extern void * C_Stack_Pointer; + extern __thread void * C_Frame_Pointer; + extern __thread void * C_Stack_Pointer; void * cfp = C_Frame_Pointer; void * csp = C_Stack_Pointer; #ifdef CL386