Branch: Tag:

2014-06-19

2014-06-19 15:55:43 by Per Hedbor <ph@opera.com>

Faster svalue type/subtype setting

The code generated for setting two shorts (on x86/x86_64 and arm at least) is
very sub-optimal, especially with gcc, for some reason:

Old push_int(0):
movq Pike_interpreter_pointer(%rip), %rdx
movq (%rdx), %rax
leaq 16(%rax), %rcx
movq %rcx, (%rdx)
xorl %edx, %edx
xorl %ecx, %ecx
movw %dx, (%rax)
movw %cx, 2(%rax)
movq $0, 8(%rax)

New push_int(0):
movq Pike_interpreter_pointer(%rip), %rdx
movq (%rdx), %rax
leaq 16(%rax), %rcx
movq %rcx, (%rdx)
movq $0, (%rax)
movq $0, 8(%rax)

Except for the lower number of instructions there is an additional
benefit: The old code triggered a read-modify-write operation on most
modern x86 CPU:s, all to preserve the undefined data between subtype
and the value of the svalue. This could be fixed by changing the type
and subtype to be 32-bit instead of 16-bit, but that is a bigger
change.

118:   } *opcode_to_fcode;   #endif /* HAVE_COMPUTED_GOTO */    +  +    #ifdef PIKE_DEBUG   PMOD_EXPORT extern const char msg_stack_error[];   #define debug_check_stack() do{if(Pike_sp<Pike_interpreter.evaluator_stack)Pike_fatal("%s", msg_stack_error);}while(0)
200:   #endif /* PIKE_DEBUG */      #ifdef __CHECKER__ - #define IF_CHECKER(X) X + #define SET_SVAL_TYPE_SUBTYPE_CHECKER(S,T,U) SET_SVAL_TYPE(S,Y);SET_SVAL_SUBTYPE(S,U)   #else - #define IF_CHECKER(X) + #define SET_SVAL_TYPE_SUBTYPE_CHECKER(S,T,U) SET_SVAL_TYPE(S,T)   #endif      #define pop_stack() do{ free_svalue(--Pike_sp); debug_check_stack(); }while(0)
268:      #define push_program(P) do{ \    struct program *_=(P); \ -  struct svalue *_sp_ = Pike_sp++; \ +  struct svalue *_sp_ = (struct svalue*)Pike_sp++; \    debug_malloc_touch(_); \ -  +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, PIKE_T_PROGRAM,0); \    _sp_->u.program=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_PROGRAM); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)      #define push_int(I) do{ \    INT_TYPE _=(I); \ -  struct svalue *_sp_ = Pike_sp++; \ +  struct fast_svalue *_sp_ = (struct fast_svalue*)Pike_sp++; \ +  SET_SVAL_TYPE_SUBTYPE(*_sp_, PIKE_T_INT,NUMBER_NUMBER); \    _sp_->u.integer=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_INT); \ -  SET_SVAL_SUBTYPE(*_sp_, NUMBER_NUMBER); \ +     }while(0)      #define push_undefined() do{ \ -  struct svalue *_sp_ = Pike_sp++; \ +  struct fast_svalue *_sp_ = (struct fast_svalue*)Pike_sp++; \ +  SET_SVAL_TYPE_SUBTYPE(*_sp_, PIKE_T_INT,NUMBER_UNDEFINED); \    _sp_->u.integer=0; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_INT); \ -  SET_SVAL_SUBTYPE(*_sp_, NUMBER_UNDEFINED); \ +     }while(0)      #define push_obj_index(I) do{ \    int _=(I); \    struct svalue *_sp_ = Pike_sp++; \ -  +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, T_OBJ_INDEX,0); \    _sp_->u.identifier=_; \ -  SET_SVAL_TYPE(*_sp_, T_OBJ_INDEX); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)      #define push_mapping(M) do{ \    struct mapping *_=(M); \    struct svalue *_sp_ = Pike_sp++; \    debug_malloc_touch(_); \ -  +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, PIKE_T_MAPPING,0); \    _sp_->u.mapping=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_MAPPING); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)      #define push_array(A) do{ \    struct array *_=(A); \    struct svalue *_sp_ = Pike_sp++; \    debug_malloc_touch(_); \ -  +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, PIKE_T_ARRAY,0); \    _sp_->u.array=_ ; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_ARRAY); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)      #define push_empty_array() ref_push_array(&empty_array)
322:    struct multiset *_=(L); \    struct svalue *_sp_ = Pike_sp++; \    debug_malloc_touch(_); \ +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, PIKE_T_MULTISET,0); \    _sp_->u.multiset=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_MULTISET); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)      #define push_string(S) do { \    struct pike_string *_=(S); \ -  struct svalue *_sp_ = Pike_sp++; \ +  struct fast_svalue *_sp_ = (struct fast_svalue*)Pike_sp++; \    debug_malloc_touch(_); \    DO_IF_DEBUG(if(_->size_shift & ~3) { \    Pike_fatal("Pushing string with bad shift: %d\n", \    _->size_shift); \    }); \ -  SET_SVAL_SUBTYPE(*_sp_, 0); \ +  SET_SVAL_TYPE_SUBTYPE(*_sp_, PIKE_T_STRING,0); \    _sp_->u.string=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_STRING); \ +     }while(0)      #define push_empty_string() ref_push_string(empty_pike_string)
346:    struct pike_type *_=(S); \    struct svalue *_sp_ = Pike_sp++; \    debug_malloc_touch(_); \ +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, PIKE_T_TYPE,0); \    _sp_->u.type=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_TYPE); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)    - #define push_object(O) do { \ -  struct object *_=(O); \ -  struct svalue *_sp_ = Pike_sp++; \ -  debug_malloc_touch(_); \ -  _sp_->u.object=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_OBJECT); \ -  SET_SVAL_SUBTYPE(*_sp_, 0); \ -  }while(0) + #define push_object(O) push_object_inherit(O,0)      #define push_object_inherit(O, INH_NUM) do { \    struct object *_ = (O); \ -  struct svalue *_sp_ = Pike_sp++; \ +  struct fast_svalue *_sp_ = (struct fast_svalue*)Pike_sp++; \    int _inh_ = (INH_NUM); \    debug_malloc_touch(_); \ -  +  SET_SVAL_TYPE_SUBTYPE(*_sp_, PIKE_T_OBJECT,_inh_); \    _sp_->u.object = _; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_OBJECT); \ -  SET_SVAL_SUBTYPE(*_sp_, _inh_); \ +     }while(0)      #define push_float(F) do{ \    FLOAT_TYPE _=(F); \    struct svalue *_sp_ = Pike_sp++; \ -  +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, PIKE_T_FLOAT,0); \    _sp_->u.float_number=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_FLOAT); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)      PMOD_EXPORT extern void push_text( const char *x );      #define push_constant_text(T) do{ \ -  struct svalue *_sp_ = Pike_sp++; \ -  SET_SVAL_SUBTYPE(*_sp_, 0); \ +  struct fast_svalue *_sp_ = (struct fast_svalue*)Pike_sp++; \ +  SET_SVAL_TYPE_SUBTYPE(*_sp_, PIKE_T_STRING,0); \    REF_MAKE_CONST_STRING(_sp_->u.string,T); \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_STRING); \ +     }while(0)      #define push_constant_string_code(STR, CODE) do{ \
395:      #define push_function(OBJ, FUN) do { \    struct object *_=(OBJ); \ -  struct svalue *_sp_ = Pike_sp++; \ +  struct fast_svalue *_sp_ = (struct fast_svalue*)Pike_sp++; \    debug_malloc_touch(_); \ -  +  SET_SVAL_TYPE_SUBTYPE(*_sp_, PIKE_T_FUNCTION,(FUN)); \    _sp_->u.object=_; \ -  SET_SVAL_SUBTYPE(*_sp_, (FUN)); \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_FUNCTION); \ +     } while (0)      #define ref_push_program(P) do{ \    struct program *_=(P); \    struct svalue *_sp_ = Pike_sp++; \    add_ref(_); \ -  +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, PIKE_T_PROGRAM,0); \    _sp_->u.program=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_PROGRAM); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)      #define ref_push_mapping(M) do{ \    struct mapping *_=(M); \    struct svalue *_sp_ = Pike_sp++; \    add_ref(_); \ -  +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, PIKE_T_MAPPING,0); \    _sp_->u.mapping=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_MAPPING); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)      #define ref_push_array(A) do{ \    struct array *_=(A); \    struct svalue *_sp_ = Pike_sp++; \    add_ref(_); \ -  +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, PIKE_T_ARRAY,0); \    _sp_->u.array=_ ; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_ARRAY); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)      #define ref_push_multiset(L) do{ \    struct multiset *_=(L); \    struct svalue *_sp_ = Pike_sp++; \    add_ref(_); \ -  +  SET_SVAL_TYPE_SUBTYPE_CHECKER(*_sp_, PIKE_T_MULTISET,0); \    _sp_->u.multiset=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_MULTISET); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)      #define ref_push_string(S) do{ \    struct pike_string *_=(S); \ -  struct svalue *_sp_ = Pike_sp++; \ +  struct fast_svalue *_sp_ = (struct fast_svalue*)Pike_sp++; \    DO_IF_DEBUG(if(_->size_shift & ~3) { \    Pike_fatal("Pushing string with bad shift: %d\n", \    _->size_shift); \    }); \    add_ref(_); \ -  SET_SVAL_SUBTYPE(*_sp_, 0); \ +  SET_SVAL_TYPE_SUBTYPE(*_sp_, PIKE_T_STRING,0); \    _sp_->u.string=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_STRING); \ +     }while(0)      #define ref_push_type_value(S) do{ \    struct pike_type *_=(S); \ -  struct svalue *_sp_ = Pike_sp++; \ +  struct fast_svalue *_sp_ = (struct fast_svalue*)Pike_sp++; \    add_ref(_); \ -  +  SET_SVAL_TYPE_SUBTYPE(*_sp_, PIKE_T_TYPE,0); \    _sp_->u.type=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_TYPE); \ -  IF_CHECKER(SET_SVAL_SUBTYPE(*_sp_, 0)); \ +     }while(0)    - #define ref_push_object(O) do{ \ -  struct object *_=(O); \ -  struct svalue *_sp_ = Pike_sp++; \ -  add_ref(_); \ -  _sp_->u.object=_; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_OBJECT); \ -  SET_SVAL_SUBTYPE(*_sp_, 0); \ -  }while(0) + #define ref_push_object(O) ref_push_object_inherit(O,0)      #define ref_push_object_inherit(O, INH_NUM) do{ \    struct object *_ = (O); \ -  struct svalue *_sp_ = Pike_sp++; \ -  int _inh_ = (INH_NUM); \ +  struct fast_svalue *_sp_ = (struct fast_svalue*)Pike_sp++; \    add_ref(_); \ -  +  SET_SVAL_TYPE_SUBTYPE(*_sp_, PIKE_T_OBJECT, (INH_NUM)); \    _sp_->u.object = _; \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_OBJECT); \ -  SET_SVAL_SUBTYPE(*_sp_, _inh_); \ +     }while(0)      #define ref_push_function(OBJ, FUN) do { \    struct object *_=(OBJ); \ -  struct svalue *_sp_ = Pike_sp++; \ +  struct fast_svalue *_sp_ = (struct fast_svalue*)Pike_sp++; \    add_ref(_); \ -  +  SET_SVAL_TYPE_SUBTYPE(*_sp_, PIKE_T_FUNCTION,(FUN)); \    _sp_->u.object=_; \ -  SET_SVAL_SUBTYPE(*_sp_, (FUN)); \ -  SET_SVAL_TYPE(*_sp_, PIKE_T_FUNCTION); \ +     } while (0)      #define push_svalue(S) do { \
503:    _sp_[-2]=_; \    } while(0)    + #if PIKE_T_INT+NUMBER_NUMBER==0 && defined(HAS___BUILTIN_MEMSET) + #define push_zeroes(N) do{ \ +  ptrdiff_t num_ = (N); \ +  __builtin_memset(Pike_sp,0,sizeof(struct svalue)*(num_)); \ +  Pike_sp+=num_; \ +  } while(0); + #else   #define push_zeroes(N) do{ \ -  struct svalue *s_=Pike_sp; \ +  struct fast_svalue *s_=(struct fast_svalue*)Pike_sp; \    ptrdiff_t num_= (N); \    for(;num_-- > 0;s_++) \    { \ -  SET_SVAL_TYPE(*s_, PIKE_T_INT); \ -  SET_SVAL_SUBTYPE(*s_, NUMBER_NUMBER); \ +  SET_SVAL_TYPE_SUBTYPE(*s_, PIKE_T_INT,NUMBER_NUMBER); \    s_->u.integer=0; \    } \    Pike_sp=s_; \   }while(0) -  + #endif      #define push_undefines(N) do{ \ -  struct svalue *s_=Pike_sp; \ +  struct fast_svalue *s_=(struct fast_svalue*)Pike_sp; \    ptrdiff_t num_= (N); \    for(;num_-- > 0;s_++) \    { \ -  SET_SVAL_TYPE(*s_, PIKE_T_INT); \ -  SET_SVAL_SUBTYPE(*s_, NUMBER_UNDEFINED); \ +  SET_SVAL_TYPE_SUBTYPE(*s_, PIKE_T_INT,NUMBER_UNDEFINED); \    s_->u.integer=0; \    } \    Pike_sp=s_; \