* Sat Sep 20 00:36:16 JST 2008 Naoyuki Sawa
-  構造体の戻り値を格納するアドレスの隠し引数も、エリアスセーフを注意しなければならない事について

これまで、構造体の戻り値を格納するアドレスの隠し引数には、エリアスセーフを考慮する必要は無いと思っていました。
必ず、暗黙の一時領域のアドレスが使用されるものと思っていました。
しかし、実際にはそうではなく、やはりエリアスセーフを考慮する必要が有ったようです。

なぜ、これまで前述のように思い込んでいたかと言うと、以下のようなコードのコンパイル結果を確認していたからです。

	typedef struct _POS {
		int x, y;
	} POS;

	extern POS XchgPos(const POS* p);

	POS pos;
	void Caller() {
		pos = XchgPos(&pos);
	}

このコードは、以下のようにコンパイルされます。(-O2最適化有り)

	Caller:
		xsub	%sp, %sp, 8
		ld.w	%r12, %sp
		xld.w	%r13, pos
		xcall	XchgPos
		xld.w	%r10, [%sp+0]
		xld.w	%r11, [%sp+4]
		xld.w	[pos+0], %r10
		xld.w	[pos+4], %r11
		xadd	%sp, %sp, 8
		ret

XchgPos()の結果を直接、変数posに受け取るのではなく、一時領域にいったん受け取り、その後、posにコピーしています。
直接、変数posに受け取ることもできるのに、わざわざ上記のようにコンパイルされていることから考えて、
構造体の戻り値を格納するアドレスが、入力ポインタ引数のエリアスになることはないものと思ってしまっていました。

ところが、次のようなコードをコンパイルすると、エリアスになることも有り得ることがわかりました。

	typedef struct _POS {
		int x, y, z;
	} POS;

	extern POS XchgPos(const POS* p);

	POS pos;
	void Caller() {
		pos = XchgPos(&pos);
	}

このコードは、以下のようにコンパイルされます。(-O2最適化有り)

	Caller:
		xld.w	%r12, pos
		ld.w	%r13, %r12
		xcall	XchgPos
		ret

構造体の戻り値を格納するアドレスが、入力ポインタ引数のエリアスになっています。
もし、XchgPos()を次のように実装してしまうと、エリアスセーフでなく、誤った動作になってしまいます。

	;// 誤り
	XchgPos:
		xld.w	%r4, [%r13+0]		;// %r4     := p->x
		xld.w	[%r12+8], %r4		;// 戻り値.z = p->x
		xld.w	%r4, [%r13+8]		;// %r4     := p->z
		xld.w	[%r12+0], %r4		;// 戻り値.x = p->z
		ld.w	%r10, %r12		;// (S1C33 ABI仕様)
		ret

正しくは、次のように実装しなくてはなりません。

	;// 正しい
	XchgPos:
		xld.w	%r4, [%r13+0]		;// %r4     := p->x
		xld.w	%r5, [%r13+8]		;// %r5     := p->z
		xld.w	[%r12+8], %r4		;// 戻り値.z = p->x
		xld.w	[%r12+0], %r5		;// 戻り値.x = p->z
		ld.w	%r10, %r12		;// (S1C33 ABI仕様)
		ret

エリアスになり得るかどうかは、『戻り値の構造体サイズが8バイト以下か、それよりも大きいか』に因るみたいです。
先の例では、POSの構造体サイズが8バイトなので、コンパイラはエリアスを用いないことを選択しているようです。
後の例では、POSの構造体サイズが12バイトなので、コンパイラはエリアスを用いることを選択しているようです。
以上の判断基準は推測であり、また、コンパイラの仕様にも明記されていないため、依存すべきでは有りません。

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
■構造体の戻り値を格納するアドレスについても、常にエリアスセーフを考慮して、呼び出される側の関数を実装すべきです。■
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

なお、C言語で作成した場合には、きちんとエリアスセーフを考慮したコンパイル結果になるため、危険は有りません。
注意しなければならないのは、手作業でアセンブラ版を作成する場合です。

2008/09/20現在、以下の関数のアセンブラ版に、エリアスセーフで無い問題が判明しました。
そのため、アセンブラ版をとりやめ、C言語版に戻します。

×clipflt2.cモジュールの、vec3f_intersection_p_lのアセンブラ版
　実際に、問題が生じました。

×clipflt2.cモジュールの、vec2f_intersection_lのアセンブラ版
　構造体サイズが8バイトなので、上述の特性によって問題は生じないかもしれませんが、確実では有りません。

アセンブラ版の問題を修正して、これらの関数を再びアセンブラ化するかどうかは、検討中です。
→2008/09/21追記:vec2f_intersection_lはアセンブラ版を修正しました。
→2008/09/21追記:vec3f_intersection_p_lはC言語版とアセンブラ版の違いが小さいので、C言語のままでも良いかも知れません。
→2008/09/22追記:やっぱり、vec3f_intersection_p_lもアセンブラ版を修正しました。

また、これらの他にもまだ、問題の有るアセンブラ版関数が残っている可能性があるので、引き続き調査と注意が必要です。
