New CAST instruction for Spin2

12467

Comments

  • cgraceycgracey Posts: 11,711
    edited 2019-05-23 - 01:22:32
    CASE FAST x

    How would that be?

    I think there needs to be some invocation beyond inference, so that the user is sure he's meeting the requirements and getting the desired performance.
  • Chip, how about "CASEN", since it's a 1 of N CASE statement?

    JUMP, GOTO, CAST, etc have *VERY* specific connotations in other languages, they should not be overloaded for purposes that are not semantically equal to another language.

    If you want to use 2 words to describe it, why not make a modifier for the CASE keyword?

    DIRECT CASE

    You would modify CASE with DIRECT to indicate it is the DIRECT form of CASE.
  • pedward wrote: »
    Chip, how about "CASEN", since it's a 1 of N CASE statement?

    JUMP, GOTO, CAST, etc have *VERY* specific connotations in other languages, they should not be overloaded for purposes that are not semantically equal to another language.

    If you want to use 2 words to describe it, why not make a modifier for the CASE keyword?

    DIRECT CASE

    You would modify CASE with DIRECT to indicate it is the DIRECT form of CASE.

    How about HOTCASE ?
  • Okay, if you think you must, how about hard case and add soft case as a synonym for case?

    For awhile, I was thinking briefcase, but that's just too cute, albeit somewhat appropriate.

    I still think inference is the better choice, though; although I toyed with, but rejected, nutcase. :smile:

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • CASE BYTE x, CASEB x, BYTECASE x ? assuming branch table index is going to be limited to bytes
  • jmgjmg Posts: 13,923
    cgracey wrote: »
    How about HOTCASE ?

    If your compiler needs a directive, then CASE TABLE is clearer than HOTCASE, which sends someone to the manual to figure what that means ?
    Do you also want to allow SKIP forms of case, in compact uses ?

  • I guess one reason I favor just case is that a primary function of any high-level language is to hide the implementation details from the programmer. So I still think a paragraph in the user manual is sufficient to distinguish the semantics between the two case types without messing with the syntax.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • just Ugh.
  • Roy Eltham wrote: »
    just Ugh.
    JUST x
    
    Melbourne, Australia
  • Tonight, I will hopefully get this thing coded up.

    It is an ackowledged matter that naming is one of the biggest headaches in programming.
  • cgracey wrote: »
    Tonight, I will hopefully get this thing coded up.

    It is an ackowledged matter that naming is one of the biggest headaches in programming.

    The function itself is more important than the name.
    The name can be decided on later.

    As long as it's documented I don't really care what it's called. :lol:
    Melbourne, Australia
  • CASE BRIEF x

    Well, what I really want to say is BRIEF CASE :) :) :)

    Yeah, it's morning, so not at all serious !
  • it's best if it's something clear so it doesn't require looking up.
    which is why I like CASE TABLE x
  • Cluso99Cluso99 Posts: 15,405
    edited 2019-05-23 - 06:08:31
    @Phil,
    A specific variant is required as the programmer is calling for a specific implementation which might not be the preferred compiler method depending on the parameters/cases supplied.

    @all,
    CASE TABLE x seems to make the most sense to me. “TABLE” is only required to force a specific compiler implementation of the CASE statement. A table will be the result and it will be deterministic.
    It’s not a faster or slower implementation as that depends on the various cases (sort of like operands). Same goes for size. So brief/fast/hot or similar do not make sense.
    So I vote for NUTCASE ;)
    My Prop boards: P8XBlade2, RamBlade, CpuBlade, TriBlade
    Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
    Website: www.clusos.com
    Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
  • cgracey wrote: »
    CASE FAST x

    How would that be?

    I think there needs to be some invocation beyond inference, so that the user is sure he's meeting the requirements and getting the desired performance.

    CASE FAST is actually pretty good, I think
  • cgraceycgracey Posts: 11,711
    edited 2019-05-23 - 08:04:25
    I know this has gotten trivial, but I settled on this, for now:

    CASE_FAST x

    I wanted to keep the symbol FAST available for user purposes, so the fast case will be CASE_FAST.
  • TorTor Posts: 1,981
    I actually liked the WHEN suggestion.
  • How about TAJ, short for Table Address Jump. Then you could add MAHAL for some fancy added functionality later.
    In science there is no authority. There is only experiment.
    Life is unpredictable. Eat dessert first.
  • What about "CASEX"?
    Prop Info and Apps: http://www.rayslogic.com/
  • Rayman wrote: »
    What about "CASEX"?

    I proposed that earlier, but it didn't take.
  • Tor wrote: »
    I actually liked the WHEN suggestion.

    I like that, too. That name is actually better than CASE.
  • cgraceycgracey Posts: 11,711
    edited 2019-05-23 - 13:57:17
    It turns out that this CASE_FAST (or whatever you'd prefer to think of it as), has the same syntax as CASE, where you can put values and ranges before the ":". The ranges and values must be constants, though. And they must all be within 255 of eachother, though they can be any 32-bit values. And no more than 256 cases, plus one 'other' case for out-of-range/interstitial cases.
  • When? Really?

    Both case and whatever this address jump table method ends up being called are a method of calling 1 of n blocks of code to execute so "select", "choose", "pick", etc. would more logical names for both. If "case" was not already in common use I would have suggested SELE (or SEL=) for what is now case, and SELT for the address table jump.
    In science there is no authority. There is only experiment.
    Life is unpredictable. Eat dessert first.
  • cgraceycgracey Posts: 11,711
    edited 2019-05-23 - 18:33:18
    I've got it done.

    Here is the code that runs on the chip to make the CASE_FAST work:
    '
    '
    ' a: CASE_FAST init
    '
    ' entry:
    '   x		index
    '   ptra[-1]	address
    '
    ' exit:
    '   x		address
    '
    '
    ' b: CASE_FAST done
    '
    ' entry:
    '   x		address
    '
    casefi		rflong	y		'a	get index base
    		sub	x,y		'a	zero index
    		rfword	y		'a	get index limiter
    		fle	x,y		'a	limit index
    		shl	x,#1		'a	make into word index
    		getptr	y		'a	get rdfast pointer
    		add	x,y		'a	add rdfast pointer into word index
    		rdword	a,x		'a	read offset word
    		add	a,y		'a	add rdfast pointer into offset word
    casefd		mov	a,x		'| b	get 'done' address
    		popa	x		'a b	pop stack
    casex		add	a,pbase		'| b	add pbase
    	_ret_	rdfast	#0,a		'a b	branch to case code
    


    And here is the code in the compiler (minus a bunch of subroutines), which compiles the CASE_FAST structure. I had to replace double-at's with ** to make it display on the forum:
    ;
    ;
    ; Compile block - 'case_fast'
    ;
    cb_case_fast:	mov	ebp,[column]		;set new column
    
    		mov	al,type_case_fast	;set new 'case_fast' blocknest
    		mov	ah,case_fast_limit/16+1	;reserve case_fast_limit + 16 bstack variables
    		call	new_bnest
    
    		lea	eax,[**comp]		;optimize case_fast block
    		call	optimize_block
    
    		call	end_bnest		;done, end blocknest
    		jmp	cb_loop			;return to compile block loop
    
    
    **final_addr	=	0
    **table_ptr	=	1
    **source_ptr	=	2
    **min_value	=	3
    **max_value	=	4
    **table_address	=	5
    
    
    **comp:		mov	eax,**final_addr	;compile final address
    		call	compile_bstack_address
    
    		call	compile_exp		;compile target value
    		call	get_end
    
    		mov	al,bc_case_fast_init	;enter case_fast init
    		call	enter_obj
    
    		mov	eax,0			;enter spacer for rflong
    		call	enter_obj_long
    
    		mov	eax,0			;enter spacer for rfword
    		call	enter_obj_word
    
    		mov	ebx,[obj_ptr]		;remember jump table start
    		mov	eax,**table_ptr
    		call	write_bstack
    
    		mov	ebx,[source_ptr]	;remember source ptr
    		mov	eax,**source_ptr
    		call	write_bstack
    
    		mov	eax,**min_value		;reset min value
    		mov	ebx,7FFFFFFFh
    		call	write_bstack
    
    		mov	eax,**max_value		;reset max value
    		mov	ebx,80000000h
    		call	write_bstack
    
    
    		mov	ecx,0			;reset case count
    		mov	dl,0			;reset 'other' block flag
    
    **nextcase1:	call	get_element		;first pass determines min and max values
    		jc	**done1			;if eof, first pass done
    		cmp	al,type_end		;ignore blank lines
    		je	**nextcase1
    
    		call	get_column		;if no indention, first pass done
    		call	back_element
    		cmp	[column],ebp
    		jbe	**done1
    
    		cmp	dl,1			;if 'other' already encountered, error
    		je	error_omblc
    
    		push	ebp			;save original column
    		mov	ebp,[column]		;set new column
    
    		cmp	al,type_other		;'other' case?
    		jne	**notother1
    		mov	dl,1			;set 'other' flag
    		call	get_element		;skip 'other'
    		jmp	**getcolon1		;get colon and skip instruction block
    **notother1:
    		inc	ecx			;not 'other', must be case, inc case count
    		mov	eax,ecx
    		cmp	eax,case_fast_limit	;check case_fast limit
    		ja	error_loxcasef
    
    **nextrange1:	call	get_range		;get value/range and update min and max values
    		call	**updateminmax
    		mov	eax,ebx
    		call	**updateminmax
    **notrange1:	call	check_comma		;if comma, compound case
    		je	**nextrange1
    
    **getcolon1:	call	get_colon		;get ':' after (last) value/range
    		call	skip_block		;skip instruction block
    
    		pop	ebp			;restore original column
    		jmp	**nextcase1		;get next case
    **done1:
    
    		cmp	ecx,0			;if no value/range cases, error
    		je	error_nce
    
    		mov	eax,**table_ptr		;write min value into rflong position
    		call	read_bstack
    		push	ebx
    		mov	eax,**min_value
    		call	read_bstack
    		pop	eax
    		mov	[dword obj-6+eax],ebx
    
    		push	eax			;write max-min+1 value into rfword position
    		push	ebx
    		mov	eax,**max_value
    		call	read_bstack
    		pop	eax
    		sub	ebx,eax
    		inc	ebx
    		pop	eax
    		mov	[word obj-2+eax],bx
    
    		mov	edx,ecx			;get 'other' case in dx
    
    		mov	ecx,0			;init jump table with 'other' case
    **inittable:	mov	[word obj+eax+ecx*2],dx
    		inc	ecx
    		cmp	ecx,ebx
    		jbe	**inittable
    		shl	ecx,1			;update obj_ptr
    		add	ecx,eax
    		mov	[obj_ptr],ecx
    
    		mov	eax,**source_ptr	;point back to source after 'case_fast' line
    		call	read_bstack
    		mov	[source_ptr],ebx
    
    
    		mov	ecx,0			;reset case count
    
    **nextcase2:	call	get_element		;second pass fills in table and compiles blocks
    		jc	**done2			;if eof, second pass done
    		cmp	al,type_end		;ignore blank lines
    		je	**nextcase2
    
    		call	get_column		;if no indention, second pass done
    		call	back_element
    		cmp	[column],ebp
    		jbe	**done2
    
    		push	ebp			;save original column
    		mov	ebp,[column]		;set new column
    
    		cmp	al,type_other		;'other' case?
    		jne	**notother2
    		call	get_element		;skip 'other'
    		jmp	**getcolon2		;get colon and compile instruction block
    **notother2:
    **nextrange2:	call	get_range		;get value/range and write into jump table
    		sub	ebx,eax			;get range count into ebx
    		inc	ebx
    		push	ebx
    		push	eax			;get table start position into eax
    		mov	eax,**min_value
    		call	read_bstack
    		pop	eax
    		sub	eax,ebx
    		push	eax
    		mov	eax,**table_ptr
    		call	read_bstack
    		pop	eax
    		shl	eax,1
    		add	eax,ebx			;table pointer in eax
    		pop	ebx			;entry count in ebx
    
    **filltable:	cmp	[word obj+eax],dx	;make sure entries are unclaimed with 'other' case
    		jne	error_cfiinu
    		mov	[word obj+eax],cx	;fill table entries with case number
    		add	eax,2
    		dec	ebx
    		jnz	**filltable
    
    		call	check_comma		;if comma, compound case
    		je	**nextrange2
    
    **getcolon2:	call	get_colon		;get ':' after value/range
    
    		mov	eax,ecx			;write block address for this case
    		add	eax,**table_address
    		call	write_bstack_ptr
    
    		call	compile_block_check	;compile instruction block
    
    		inc	ecx			;inc case count
    
    		mov	eax,ecx			;write block address for potential missing 'other' case
    		add	eax,**table_address	;(points to next/last bc_case_fast_done)
    		call	write_bstack_ptr
    
    		mov	eax,**table_ptr		;make sure address offset will fit into jump table word
    		call	read_bstack
    		mov	eax,[obj_ptr]
    		sub	eax,ebx
    		cmp	eax,0FFFFh
    		ja	error_cfbex
    
    		mov	al,bc_case_fast_done	;(case fast done)
    		call	enter_obj
    
    		pop	ebp			;restore original column
    		jmp	**nextcase2		;get next case
    **done2:
    		mov	eax,**final_addr	;write final address
    		call	write_bstack_ptr
    
    
    		mov	eax,**table_ptr		;replace case numbers with block offsets in jump table
    		call	read_bstack
    		movzx	ecx,[word obj-2+ebx]	;get jump table count in ecx
    		inc	ecx
    		mov	edx,ebx			;get jump table offset in edx
    
    **replace:	movzx	eax,[word obj+ebx]	;get case index from jump table
    		push	ebx
    		add	eax,**table_address	;use case index to look up case block offset
    		call	read_bstack
    		mov	eax,ebx
    		sub	eax,edx
    		pop	ebx
    		mov	[word obj+ebx],ax	;write case block offset into jump table
    		add	ebx,2			;loop until all cases + 'other' handled
    		loop	**replace
    
    		ret
    
    
    
    **updateminmax:	push	eax			;update min and max values with eax
    		push	ebx
    		push	ecx
    
    		mov	ecx,eax
    
    		mov	eax,**min_value		;update min value
    		call	read_bstack
    		cmp	ecx,ebx
    		jge	**notmin
    		mov	ebx,ecx
    		call	write_bstack
    **notmin:
    		mov	eax,**max_value		;update max value
    		call	read_bstack
    		cmp	ecx,ebx
    		jle	**notmax
    		mov	ebx,ecx
    		call	write_bstack
    **notmax:
    		call	read_bstack		;check for span violation
    		mov	ecx,ebx
    		mov	eax,**min_value
    		call	read_bstack
    		sub	ecx,ebx
    		cmp	ecx,255
    		ja	error_cfvmbw
    
    		pop	ecx
    		pop	ebx
    		pop	eax
    		ret
    

    This is a real pain in 80386 and it's made worse by this code being recursively called, making it necessary to implement some software stack to augment the limited register set. This would be so much easier to do in Spin2, or any high-level language. In assembly, you've often got to type a lot to make things like conditional sequences, anyway.
  • x86 is a terrible architecture to begin with. Fun times when you have a multi-GHz CPU with only 6 usable registers (more I guess if you can use al/ah etc. as separate things, but that slows it down a bunch). amd64 at least adds some more registers (as well as guaranteeing SSE2...). ARM and POWER still have twice that. Yikes.

    I haven't read the code thoroughly, but is there a particular reason to use a software stack as opposed to the hardware one?
  • cgraceycgracey Posts: 11,711
    edited 2019-05-23 - 19:14:03
    I probably should have used the stack hardware, instead, but I have never done it. So, I just built one in software. I bet it hurts more this way.
  • jmgjmg Posts: 13,923
    cgracey wrote: »
    I've got it done.

    Here is the code that runs on the chip to make the CASE_FAST work:
    Do you plan to do a compact CASE that uses DECOD and SKIP opcode(s) ?
    It is common for there to be rather less than 256 choices so one that supports up to 32 would be useful, and I think can be smaller again ?


  • jmg wrote: »
    cgracey wrote: »
    I've got it done.

    Here is the code that runs on the chip to make the CASE_FAST work:
    Do you plan to do a compact CASE that uses DECOD and SKIP opcode(s) ?
    It is common for there to be rather less than 256 choices so one that supports up to 32 would be useful, and I think can be smaller again ?


    No plans. For contiguous cases, this only uses 1 word per case branch. I don't think it could get any smaller, or faster.
  • jmgjmg Posts: 13,923
    cgracey wrote: »
    jmg wrote: »
    Do you plan to do a compact CASE that uses DECOD and SKIP opcode(s) ?
    It is common for there to be rather less than 256 choices so one that supports up to 32 would be useful, and I think can be smaller again ?

    No plans. For contiguous cases, this only uses 1 word per case branch. I don't think it could get any smaller, or faster.

    There is quite a bit of housekeeping in the table preamble, whilst I expected DECOD and SKIP/SKIPF to largely work in 2~3 lines plus up to 32 jumps. Did I miss something ?
  • cgracey wrote: »
    This is a real pain in 80386 and it's made worse by this code being recursively called, making it necessary to implement some software stack to augment the limited register set. This would be so much easier to do in Spin2, or any high-level language. In assembly, you've often got to type a lot to make things like conditional sequences, anyway.

    You're planning to port the compiler to Spin2 eventually anyway, aren't you? So why not do that now, and save yourself the trouble of doing all this 80386 programming?

Sign In or Register to comment.