/*	
 *	clipdi.c
 *
 *	下位レベル関数 : 64ビット整数演算ライブラリ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2015 Naoyuki Sawa
 *
 *	* Sun Feb  6 06:09:00 JST 2005 Naoyuki Sawa
 *	- 64ビット整数演算ライブラリは、きわめて使用頻度が低いので、
 *	  不要なアプリケーションにリンクされてサイズが無駄に増えるのを防ぐために、
 *	  clippce.c -> clipdi.cへ移しました。
 *	* Thu Apr 28 22:30:00 JST 2005 Naoyuki Sawa
 *	- __ashldi3,__ashrdi3,__lshrdi3を追加しました。
 *	  long long型またはunsigned long long型を、変数でシフトするときに呼ばれます。
 *	  固定値でシフトするときは、これらの関数は呼ばれません。
 *	  <例>
 *		long long a = get_value();
 *		int b = get_shift_count();
 *		long long c = get_value();
 *		a >>= b; // "a=__ashrdi3(a,b);"に相当するコードが生成されます。
 *		c >>= 1; // __ashrdi3は使わず、インラインコードで処理されます。
 *	* Wed Feb 01 12:40:39 JST 2012 Naoyuki Sawa
 *	- __cmpdi2,__ucmpdi2を実装しました。
 *	* Thu Jan 22 21:57:39 JST 2015 Naoyuki Sawa
 *	- __udivdi3のバグを修正しました。
 *	  無条件分岐すべきなのに条件分岐していたバグでした。
 *	- __div10,__div11のバグを修正しました。
 *	  %r13:%r12に剰余を返すべきなのに%r12を破壊していたバグでした。
 */
#include "clip.h"

/****************************************************************************
 *	下位レベル関数 : 64ビット整数演算ライブラリ
 ****************************************************************************/

/* * Cコンパイラ(gcc33)自体はlong longを認識し、ちゃんとコードも生成するのですが、
 *   64ビット整数演算ライブラリが含まれていないので、使えませんでした。
 *   そこで、64ビット整数演算ライブラリを自前で実装してみました。
 *
 * * 本当は、idiv.lib(整数剰余演算ライブラリ)やfp.lib(浮動小数点演算ライブラリ)、
 *   fpp.lib(浮動小数点ライブラリ)と同様に、コンパイラに付いて来るべきものだと思うのですが、
 *   なぜか含まれていません。
 *   P/ECEの配布セットに入れ忘れたというのではなく、EPSONの配布セットに入っていないようです。
 *   （Cコンパイラマニュアルのライブラリ一覧にも載っていないことから推測）
 *   もしかしたら、gcc33の long long 演算の出力コードに問題があったりして、
 *   対応から外してしまったのかも知れません。
 *   しかし、実験した限りでは正しいコードが生成されているように見えましたので、
 *   64ビット整数演算ライブラリさえ用意すれば long long が普通に使えると判断しました。
 *   今のところ、ちゃんと動いているように思います。
 *
 * * 戻り値・引数を宣言してはいけません！
 *   宣言すると、余計なプロローグ・エピローグコードが生成されてしまいます。
 *
 * * 浮動小数点数値⇔long longの変換サポート関数は未実装です。
 *   __fixsfdi,__fixunssfdi,__floatdisfなどが呼ばれるようです。
 *   また、floatからlong longへ変換するときに、__cmpdi2という関数も呼ばれます。
 *   名前から推測するとlong longの比較関数のようですが、他では使われる様子がありません。
 *   通常のlong longの比較処理では、Cコンパイラがインラインコードを生成しているのです。
 *   なぜfloatからlong longへの変換時だけ、__cmpdi2が呼ばれるのか不明です。
 *   ⇒2012/02/01追記:__cmpdi2,__ucmpdi2を実装しました。
 *
 * * 64ビット定数のサフィックスは「ll」(符号付き)「ull」（符号無し）です。
 *   これらのサフィックスを付けなくても、大きな定数はちゃんと64ビットとして認識されますが、
 *   コンパイル時に警告が表示されます。
 *   <例>
 *	long long a = 1000000000000000000;   // 警告（動作はＯＫ）
 *	long long b = 1000000000000000000ll; // ＯＫ
 */

void/*long long*/
__negdi2(/*long long a*/) /* 符号反転 */
{
	asm("
	ld.w %r10, 0		; %r11:%r10 = 0:0 - %r13:%r12
	ld.w %r11, 0
	sub %r10, %r12
	sbc %r11, %r13
	");
}

void/*long long*/
__adddi3(/*long long a, long long b*/) /* 加算 */
{
	asm("
	ld.w %r10, %r12		; %r11:%r10 = %r13:%r12 + %r15:%r14
	ld.w %r11, %r13
	add %r10, %r14
	adc %r11, %r15
	");
}

void/*long long*/
__subdi3(/*long long a, long long b*/) /* 減算 */
{
	asm("
	ld.w %r10, %r12		; %r11:%r10 = %r13:%r12 - %r15:%r14
	ld.w %r11, %r13
	sub %r10, %r14
	sbc %r11, %r15
	");
}

#if 0 /* 0:乗算器を利用した高速版を使用/1:古典的な低速版を使用 */
///* * 古典的な筆算型の乗算ルーチンです。
// *   「64ビット×64ビット→64ビット」なので、符号を考慮する必要はありません。
// *   実際にgcc33は、64ビット乗算の場合は符号付き・符号無しに関わらず、
// *   __muldi3を呼び出すコードを生成するようです。（__umuldi3はありません）
// * * ちょっとしたテクニックのメモ：
// *   S1C33にはキャリーフラグ込みのシフト・ローテートがありません。
// *   乗数を1ビットづつ右シフトして最下位ビットを調べる必要がありますが、
// *   複数レジスタを連結して右シフトする処理は、まともに書くと非常に長くなります。
// *   例えば、%r15と%r14を連結して右1ビットシフトする処理は、こんな感じになります。
// *	ld.w %r4, %r15	; %r4'31 = %r15'0
// *	xsll %r4, 31	; ←3命令必要です
// *	srl %r15, 1
// *	srl %r14, 1
// *	or %r14, %r4
// *   Cコンパイラは、左1ビットシフトについても同様のコードを生成しますが、
// *   もっと簡単な方法があります。
// *	add %r14, %r14
// *	adc %r15, %r15	; C <- %r15'31
// *   さて、筆算型乗算ルーチンでは、乗数を最下位ビットから調べて行くので、右シフトが必要です。
// *   しかしながら前述の通り、S1C33 CPUでは、左シフト処理に較べて右シフト処理は難しいのです。
// *   そこで、乗数の全ビットを左右反転させてしまいましょう。
// *   そうしておけば、簡単な左シフトを使いながら、最上位ビットを調べればいいことになります。
// *	swap %r14, %r14		; %r14:%r15 = 左右反転(%r15:%r14)
// *	mirror %r14, %r14	; レジスタは入れ替えないので、反転後は%r14が上位になることに注意
// *	swap %r15, %r15
// *	mirror %r15, %r15
// *  S1C33のシフト・ローテート命令では、最上位ビットは単に捨てられてしまいますが、
// *  add/adcによる左シフト処理なら、最上位ビットがキャりーフラグに入るので、
// *  左シフト後にキャリーフラグを調べるだけで済みます。
// */
//void/*long long*/
//__muldi3(/*long long a, long long b*/) /* 乗算 */
//{
//	asm("
//	ld.w %r10, 0		; %r11:%r10 = 0:0
//	ld.w %r11, 0
//	swap %r14, %r14		; %r14:%r15 = 左右反転(%r15:%r14)
//	mirror %r14, %r14
//	swap %r15, %r15
//	mirror %r15, %r15
//__muldi3_L10:
//	add %r15, %r15		; C:%r14:%r15 <<= 1
//	adc %r14, %r14
//	jruge __muldi3_L30	; if(C) {
//	add %r10, %r12		;   %r11:%r10 += %r13:%r12
//	adc %r11, %r13
//__muldi3_L20:
//	add %r12, %r12		;   %r13:%r12 <<= 1
//	jp.d __muldi3_L10	;   goto L10
//	adc %r13, %r13
//__muldi3_L30:			; } else {
//	jrne __muldi3_L20	;   if(%r14 != 0) goto L20
//	or %r15, %r15		;   if(%r15 != 0) goto L20
//	jrne __muldi3_L20
//				; }
//	");
//}
#else /* 2003/03/22↓高速版に置き換えました。↑念のため低速版も残してありますが、高速版の安定が確認できたら、低速版は消してください。 */
/* 乗算器を利用した『(符号付き32bit) * (符号付き32bit) => (符号付き64bit)』
 * 
 * [in]
 * 	%r13:%r12 = ah:al
 * 	%r15:%r14 = bh:bl
 * 
 * [out]
 * 	%r11:%r10 = ((long long)(unsigned)al * (long long)(unsigned)bl <<  0)
 * 	          + ((long long)(unsigned)al * (long long)(  signed)bh << 32)
 * 	          + ((long long)(  signed)ah * (long long)(unsigned)bl << 32)
 * 	          + ((long long)(  signed)ah * (long long)(  signed)bh << 64)
 * 
 * 	最後の項は結果のビット数(64bit)よりも上のビットなので、省略できます。
 * 
 * 	%r11:%r10 = ((long long)(unsigned)al * (long long)(unsigned)bl <<  0)
 * 	          + ((long long)(unsigned)al * (long long)(  signed)bh << 32)
 * 	          + ((long long)(  signed)ah * (long long)(unsigned)bl << 32)
 * 
 * [note]
 * 	S1C33の乗算命令では、「(符号なし32bit) * (符号付き32bit)」ができません。
 * 	そこで、次のようにアレンジします。
 * 
 * 	(a=正,b=正)の場合:
 * 	%r11:%r10 = ((long long)(unsigned) al * (long long)(unsigned) bl <<  0)
 * 	          + ((long long)(unsigned) al * (long long)(unsigned) bh << 32)
 * 	          + ((long long)(unsigned) ah * (long long)(unsigned) bl << 32)
 * 
 * 	(a=正,b=負)の場合:
 * 	%r11:%r10 = ((long long)(unsigned) al * (long long)(unsigned) bl <<  0)
 * 	          - ((long long)(unsigned) al * (long long)(unsigned)-bh << 32)
 * 	          + ((long long)(unsigned) ah * (long long)(unsigned) bl << 32)
 * 
 * 	(a=負,b=正)の場合:
 * 	%r11:%r10 = ((long long)(unsigned) al * (long long)(unsigned) bl <<  0)
 * 	          + ((long long)(unsigned) al * (long long)(unsigned) bh << 32)
 * 	          - ((long long)(unsigned)-ah * (long long)(unsigned) bl << 32)
 * 
 * 	(a=負,b=負)の場合:
 * 	%r11:%r10 = ((long long)(unsigned) al * (long long)(unsigned) bl <<  0)
 * 	          - ((long long)(unsigned) al * (long long)(unsigned)-bh << 32)
 * 	          - ((long long)(unsigned)-ah * (long long)(unsigned) bl << 32)
 * 
 * [note]
 * 	と思ったのですが、よく考えたら、入出力のビット数が同じ場合は、演算の正負は関係ありませんでした。
 * 	（入出力ビット数が同じなら、入力値の最上位ビットを符号拡張することもないので）
 * 	従って、全て符号なしとみなして演算できます。
 * 
 * 	a,bの正負に関わらず:
 * 
 * 	%r11:%r10 = ((long long)(unsigned)al * (long long)(unsigned)bl <<  0)
 * 	          + ((long long)(unsigned)al * (long long)(unsigned)bh << 32)
 * 	          + ((long long)(unsigned)ah * (long long)(unsigned)bl << 32)
 */
void/*long long*/
__muldi3(/*long long a, long long b*/) /* 符号付き乗算 */
{
	asm("
	mltu.w %r12, %r14	;   al * bl <<  0
	ld.w %r10, %alr
	ld.w %r11, %ahr
	mltu.w %r12, %r15	; + al * bh << 32
	ld.w %r4, %alr
	add %r11, %r4
	mltu.w %r13, %r14	; + ah * bl << 32
	ld.w %r4, %alr
	add %r11, %r4
	");
}
#endif

/* __divdi3/__udivdi3のサポート関数。
 * S1C33000コアCPUマニュアルのdiv0s/12s/3sの詳細説明どおりに実装しました。
 * * ゼロ除算例外は生成しません。
 * * S1C33の関数呼び出し規約どおり、%r11:%r10に商を返します。
 *   さらに加えて、%r13:%r12に余りを返します。（__moddi3/__umoddi3で使っています）
 *   本当は、%r13:%r12に戻り値をセットしても、ちゃんと返されるかどうか保証されないのですが、
 *   とりあえずこれらの関数はプロローグ・エピローグコードを含まないので、大丈夫みたいです。
 * * __divdi3/__udivdi3からしか使わないので、static関数にした方がいいのですが、そうすると、
 *   Cコンパイラが「使われていないstaic関数があります」という意味の警告を出してしまいます。
 *   Cコンパイラは、__divdi3/__udivdi3の中のasm()ブロックからの呼び出しを認識しないからです。
 *   仕方がないので、グローバル関数にしてあります。
 *   →2003/03/22 __attribute__((unused))を利用して、static関数にしました。
 * * div3sの符号反転処理がちょっと苦しいですが、「adc %rd, imm6」がないので止むを得ません...
 *   「adc %rd, imm6」があれば「not %r10,%r10; not %r11,%r11; add %r10,1; adc %r11,0」とできるのに。
 *   でもまあ命令数は1つしか違わないし、サイクル数も最大2しか違わないので、たいして変わらないかな？
 * * まだテストが不十分なので、もしかしたらバグが残ってるかも知れません。
 */
static void/*long long*/ __div00(/*long long a, long long b*/) __attribute__((unused)); /* asmブロックから使うのでCコンパイラが使用を検出できない */
static void/*long long*/ __div01(/*long long a, long long b*/) __attribute__((unused)); /* asmブロックから使うのでCコンパイラが使用を検出できない */
static void/*long long*/ __div10(/*long long a, long long b*/) __attribute__((unused)); /* asmブロックから使うのでCコンパイラが使用を検出できない */
static void/*long long*/ __div11(/*long long a, long long b*/) __attribute__((unused)); /* asmブロックから使うのでCコンパイラが使用を検出できない */
static void/*long long*/
__div00(/*long long a, long long b*/) /* 正÷正 */
{
	asm("
	;***** div0s *****
	ld.w %r10, %r12		; %r13:%r12:%r11:%r10 = 0:0:%r13:%r12
	ld.w %r11, %r13
	ld.w %r12, 0
	ld.w %r13, 0
	;***** div1 *****
	xld.w %r4, 64		; %r4 = 64
__div00_L10:
	add %r10, %r10		; %r13:%r12:%r11:%r10 <<= 1
	adc %r11, %r11
	adc %r12, %r12
	adc %r13, %r13
	sub %r12, %r14		; %r13:%r12 -= %r15:%r14
	sbc %r13, %r15
	jrult __div00_L20	; if(!C) {
	jp.d __div00_L30	;   %r10'0 = 1
	or %r10, 1
__div00_L20:			; } else {
	add %r12, %r14		;   %r13:%r12 += %r15:%r14
	adc %r13, %r15
__div00_L30:			; }
	sub %r4, 1		; if(--%r4) goto L10
	jrne __div00_L10
	;***** div2s *****
	;***** div3s *****
	");
}
static void/*long long*/
__div01(/*long long a, long long b*/) /* 正÷負 */
{
	asm("
	;***** div0s *****
	ld.w %r10, %r12		; %r13:%r12:%r11:%r10 = 0:0:%r13:%r12
	ld.w %r11, %r13
	ld.w %r12, 0
	ld.w %r13, 0
	;***** div1 *****
	xld.w %r4, 64		; %r4 = 64
__div01_L10:
	add %r10, %r10		; %r13:%r12:%r11:%r10 <<= 1
	adc %r11, %r11
	adc %r12, %r12
	adc %r13, %r13
	add %r12, %r14		; %r13:%r12 += %r15:%r14
	adc %r13, %r15
	jruge __div01_L20	; if(C) {
	jp.d __div01_L30	;   %r10'0 = 1
	or %r10, 1
__div01_L20:			; } else {
	sub %r12, %r14		;   %r13:%r12 -= %r15:%r14
	sbc %r13, %r15
__div01_L30:			; }
	sub %r4, 1		; if(--%r4) goto L10
	jrne __div01_L10
	;***** div2s *****
	;***** div3s *****
	not %r10, %r10		; %r11:%r10 = -%r11:%r10
	add %r10, 1
	jruge.d __div01_L60
	not %r11, %r11
	add %r11, 1
__div01_L60:
	");
}
static void/*long long*/
__div10(/*long long a, long long b*/) /* 負÷正 */
{
	asm("
	;***** div0s *****
	ld.w %r10, %r12		; %r13:%r12:%r11:%r10 = -1:-1:%r13:%r12
	ld.w %r11, %r13
	ld.w %r12, -1
	ld.w %r13, -1
	;***** div1 *****
	xld.w %r4, 64		; %r4 = 64
__div10_L10:
	add %r10, %r10		; %r13:%r12:%r11:%r10 <<= 1
	adc %r11, %r11
	adc %r12, %r12
	adc %r13, %r13
	add %r12, %r14		; %r13:%r12 += %r15:%r14
	adc %r13, %r15
	jrult __div10_L20	; if(!C) {
	jp.d __div10_L30	;   %r10'0 = 1
	or %r10, 1
__div10_L20:			; } else {
	sub %r12, %r14		;   %r13:%r12 -= %r15:%r14
	sbc %r13, %r15
__div10_L30:			; }
	sub %r4, 1		; if(--%r4) goto L10
	jrne __div10_L10
	;***** div2s *****
	add %r12, %r14		; %r13:%r12 += %r15:%r14
	adc %r13, %r15
    ;//{{2015/01/22修正:__div10,__div11のバグを修正しました。%r13:%r12に剰余を返すべきなのに%r12を破壊していたバグでした。
    ;//	or %r12, %r13
    ;//↓2015/01/22修正:__div10,__div11のバグを修正しました。%r13:%r12に剰余を返すべきなのに%r12を破壊していたバグでした。
	ld.w %r9, %r12
	or   %r9, %r13
    ;//}}2015/01/22修正:__div10,__div11のバグを修正しました。%r13:%r12に剰余を返すべきなのに%r12を破壊していたバグでした。
	jrne __div10_L40	; if(%r13:%r12 == 0) {
	add %r10, 1		;   %r11:%r10 += 1
	jruge __div10_L50
	jp.d __div10_L50
	add %r11, 1
__div10_L40:			; } else {
	sub %r12, %r14		;   %r13:%r12 -= %r15:%r14
	sbc %r13, %r15
__div10_L50:			; }
	;***** div3s *****
	not %r10, %r10		; %r11:%r10 = -%r11:%r10
	add %r10, 1
	jruge.d __div10_L60
	not %r11, %r11
	add %r11, 1
__div10_L60:
	");
}
static void/*long long*/
__div11(/*long long a, long long b*/) /* 負÷負 */
{
	asm("
	;***** div0s *****
	ld.w %r10, %r12		; %r13:%r12:%r11:%r10 = -1:-1:%r13:%r12
	ld.w %r11, %r13
	ld.w %r12, -1
	ld.w %r13, -1
	;***** div1 *****
	xld.w %r4, 64		; %r4 = 64
__div11_L10:
	add %r10, %r10		; %r13:%r12:%r11:%r10 <<= 1
	adc %r11, %r11
	adc %r12, %r12
	adc %r13, %r13
	sub %r12, %r14		; %r13:%r12 -= %r15:%r14
	sbc %r13, %r15
	jruge __div11_L20	; if(C) {
	jp.d __div11_L30	;   %r10'0 = 1
	or %r10, 1
__div11_L20:			; } else {
	add %r12, %r14		;   %r13:%r12 += %r15:%r14
	adc %r13, %r15
__div11_L30:			; }
	sub %r4, 1		; if(--%r4) goto L10
	jrne __div11_L10
	;***** div2s *****
	sub %r12, %r14		; %r13:%r12 -= %r15:%r14
	sbc %r13, %r15
    ;//{{2015/01/22修正:__div10,__div11のバグを修正しました。%r13:%r12に剰余を返すべきなのに%r12を破壊していたバグでした。
    ;//	or %r12, %r13
    ;//↓2015/01/22修正:__div10,__div11のバグを修正しました。%r13:%r12に剰余を返すべきなのに%r12を破壊していたバグでした。
	ld.w %r9, %r12
	or   %r9, %r13
    ;//}}2015/01/22修正:__div10,__div11のバグを修正しました。%r13:%r12に剰余を返すべきなのに%r12を破壊していたバグでした。
	jrne __div11_L40	; if(%r13:%r12 == 0) {
	add %r10, 1		;   %r11:%r10 += 1
	jruge __div11_L50
	jp.d __div11_L50
	add %r11, 1
__div11_L40:			; } else {
	add %r12, %r14		;   %r13:%r12 += %r15:%r14
	adc %r13, %r15
__div11_L50:			; }
	;***** div3s *****
	");
}

/* * ちょっとしたテクニックのメモ：
 *   S1C33には、N(符号)フラグによる条件分岐がありません。
 *   だから、Z80やx86で使っていたような、こんな感じのコードは使えません。
 *	or a
 *	jp m, (負値の処理)
 *	(正値の処理)
 *   andで調べてもいいですが、0x80000000とのandは高くつきます。
 *	xand %r13, 0x80000000	; ←3命令必要です
 *	jrne (負値の処理)
 *	(正値の処理)
 *   そこで、scan1を使いましょう。
 *   scan1は、最上位ビットに1を発見した場合のみ、Zフラグがセットされます。
 *   （なぜなら、デスティネーションレジスタが0になるからです。）
 *	scan1 %r4, %r13		; %r4は破壊されることに注意！
 *	jreq.d (負値の処理)
 *	(正値の処理)
 *   scan0/1は一見複雑そうで複数サイクル命令かと思ってしまいますが、1サイクル命令です。
 *   ディレイド命令にもできますよ。
 * * Sat Mar 22 19:00:00 JST 2003 Naoyuki Sawa
 *   ↑でscan1命令による正負判断について書きましたが、良く考えたらそんなトリッキーなことしなくても、cmp命令でOKでした。
 *   「cmp sign6」も「scan1」と同じく、ディレイド可能な1サイクル命令です。
 *	cmp %r13, 0
 *	jrlt.d (負値の処理)
 *	(正値の処理)
 *   または
 *	cmp %r13, 0
 *	jrge.d (正値の処理)
 *	(負値の処理)
 *   scan1を使った場合は%r4（または空きレジスタのいずれか）が破壊されていましたが、cmpなら破壊レジスタはありません。
 *   何より、scan1で正負判断するよりも、cmpで正負判断した方が見た目に自然です。
 */
#if 0 /* 0:正負判断にcmp 0を使う/1:正負判断にscan1を使う */
//void/*long long*/
//__divdi3(/*long long a, long long b*/) /* 符号付き除算 */
//{
//	asm("
//	scan1 %r4, %r13
//	xjreq.d __divdi3_L10
//	scan1 %r4, %r15
//	xjrne __div00
//	xjp   __div01
//__divdi3_L10:
//	xjrne __div10
//	xjp   __div11
//	");
//}
#else /* 2003/03/22↓正負判断をscan1からcmp 0に変更。↑念のためscan1版も残してありますが、cmp 0版の安定が確認できたら、scan1版は消してください。 */
void/*long long*/
__divdi3(/*long long a, long long b*/) /* 符号付き除算 */
{
	asm("
	cmp %r13, 0
	xjrlt.d __divdi3_L10
	cmp %r15, 0
	xjrge __div00
	xjp   __div01
__divdi3_L10:
	xjrge __div10
	xjp   __div11
	");
}
#endif

void/*long long*/
__udivdi3(/*long long a, long long b*/) /* 符号無し除算 */
{
	asm("
    ;//{{2015/01/22修正:__udivdi3のバグを修正しました。無条件分岐すべきなのに条件分岐していたバグでした。
    ;//	xjrne __div00
    ;//↓2015/01/22修正:__udivdi3のバグを修正しました。無条件分岐すべきなのに条件分岐していたバグでした。
	xjp __div00
    ;//}}2015/01/22修正:__udivdi3のバグを修正しました。無条件分岐すべきなのに条件分岐していたバグでした。
	");
}

void/*long long*/
__moddi3(/*long long a, long long b*/) /* 符号付き剰余 */
{
	asm("
	xcall __divdi3
	ld.w %r10, %r12
	ld.w %r11, %r13
	");
}

void/*long long*/
__umoddi3(/*long long a, long long b*/) /* 符号無し剰余 */
{
	asm("
	xcall __udivdi3
	ld.w %r10, %r12
	ld.w %r11, %r13
	");
}

void/*long long*/
__ashldi3(/*long long a, int b*/) /* 算術左シフト */
{
	asm("
	xcmp	%r14, 0		; if(b > 0) {
	xjrle	__ashldi3_L20	;   
	xcmp	%r14, 64	;   if(b > 64) {
	xjrle	__ashldi3_L10	;     b = 64
	xld.w	%r14, 64	;   }
__ashldi3_L10:			;   do {
	add	%r12, %r12	;     %r12 = llllllll_llllllll_llllllll_lllllll0, %psr(C) = l
	adc	%r13, %r13	;     %r13 = hhhhhhhh_hhhhhhhh_hhhhhhhh_hhhhhhhl
	xsub	%r14, %r14, 1	;   } while(--b)
	xjrne	__ashldi3_L10	;  
__ashldi3_L20:			; }
	ld.w	%r10, %r12
	ld.w	%r11, %r13
	");
}

/* 左シフトは算術も論理も同じなので、__lshldi3は有りません。 */

void/*long long*/
__ashrdi3(/*long long a, int b*/) /* 算術右シフト */
{
	asm("
	xcmp	%r14, 0		; if(b > 0) {
	xjrle	__ashrdi3_L20	;   
	xcmp	%r14, 64	;   if(b > 64) {
	xjrle	__ashrdi3_L10	;     b = 64
	xld.w	%r14, 64	;   }
__ashrdi3_L10:			;   do {
	xand	%r9, %r13, 1	;     %r9  = 00000000_00000000_00000000_0000000h
	xand	%r12, %r12, -2	;     %r12 = llllllll_llllllll_llllllll_lllllll0
	or	%r12, %r9	;     %r12 = llllllll_llllllll_llllllll_lllllllh
	xrr	%r12, 1		;     %r12 = hlllllll_llllllll_llllllll_llllllll
	xsra	%r13, 1		;     %r13 = shhhhhhh_hhhhhhhh_hhhhhhhh_hhhhhhhh
	xsub	%r14, %r14, 1	;   } while(--b)
	xjrne	__ashrdi3_L10	;  
__ashrdi3_L20:			; }
	ld.w	%r10, %r12
	ld.w	%r11, %r13
	");
}

void/*long long*/
__lshrdi3(/*long long a, int b*/) /* 論理右シフト */
{
	asm("
	xcmp	%r14, 0		; if(b > 0) {
	xjrle	__lshrdi3_L20	;   
	xcmp	%r14, 64	;   if(b > 64) {
	xjrle	__lshrdi3_L10	;     b = 64
	xld.w	%r14, 64	;   }
__lshrdi3_L10:			;   do {
	xand	%r9, %r13, 1	;     %r9  = 00000000_00000000_00000000_0000000h
	xand	%r12, %r12, -2	;     %r12 = llllllll_llllllll_llllllll_lllllll0
	or	%r12, %r9	;     %r12 = llllllll_llllllll_llllllll_lllllllh
	xrr	%r12, 1		;     %r12 = hlllllll_llllllll_llllllll_llllllll
	xsrl	%r13, 1		;     %r13 = 0hhhhhhh_hhhhhhhh_hhhhhhhh_hhhhhhhh
	xsub	%r14, %r14, 1	;   } while(--b)
	xjrne	__lshrdi3_L10	;  
__lshrdi3_L20:			; }
	ld.w	%r10, %r12
	ld.w	%r11, %r13
	");
}

/* * Wed Feb 01 12:40:39 JST 2012 Naoyuki Sawa
 * - __cmpdi2,__ucmpdi2を実装しました。
 * - これまで、__cmpdi2,__ucmpdi2の仕様が不明でした。
 *   EPSONライブラリに含まれておらず、S1C33のコンパイラマニュアルにも記載が無かったためです。
 *   今回、S1C17のコンパイラマニュアルの中に、__cmpdi2,__ucmpdi2の仕様を見つけました。
 *   S1C17とS1C33は別のCPUですが、同じメーカーなので、たぶん同じ関数仕様だと思います。
 *   ┃「S5U1C17001C Manual (S1C17 Family Cコンパイラパッケージ) (Ver. 1.5.0)」
 *   ┃7.2.5 long long型演算関数　より引用：
 *   ┃┌────────┬─────┬──────────────────────┐
 *   ┃│      分類      │  関数名  │                     機能                   │
 *   ┃├────────┼─────┼────────────┬─────────┤
 *   ┃│long long型比較 │__cmpdi2  │比較(long long)         │x ← 2 | 1 | 0  *1│
 *   ┃│                │__ucmpdi2 │比較(unsigned long long)│x ← 2 | 1 | 0  *1│
 *   ┃└────────┴─────┴────────────┴─────────┘
 *   ┃*1 整数比較関数およびlong long比較関数はop1 - op2の結果により、以下の値を返します。
 *   ┃   op1 > op2 → 2
 *   ┃   op1 = op2 → 1
 *   ┃   op1 < op2 → 0
 */
asm("
		.code
		.align		1
		.global		__cmpdi2
		.global		__ucmpdi2
__cmpdi2:
		;// %r13:%r12 := (long long) op1
		;// %r15:%r14 := (long long) op2
		ld.w		%r9, 1		;// 符号無し比較できるよう、+(2^31)オフセットしておく
		rr		%r9, 1		;// %r9       :=        (2^31)
		add		%r13, %r9	;// %r13:%r12 := op1 += (2^31)
		add		%r15, %r9	;// %r15:%r14 := op2 += (2^31)
__ucmpdi2:
		;// %r13:%r12 := (unsigned long long) op1
		;// %r15:%r14 := (unsigned long long) op2
		cmp		%r13, %r15	;// if(op1H != op2H) %psr(C,Z) := op1H <=> op2H
		jrne		2
		 cmp		%r12, %r14	;// if(op1H == op2H) %psr(C,Z) := op1L <=> op2L
		jrult.d		5
		 ld.w		%r10, 0		;// if(op1 <  op2) %r10 := 0	*delay*
		 jreq.d		3
		  ld.w		%r10, 1		;// if(op1 == op2) %r10 := 1	*delay*
		  ld.w		%r10, 2		;// if(op1 >  op2) %r10 := 2
		ret
");
