こんにちは。NoMaYです。e2 studio v6.3.0がリリースされていたので、インストールして幾つかプロジェクトを作成して、いつものようにe2 studioのインストールフォルダを眺めていたら、CCRXmachine.hとCCRXmachine.cというファイルがあることに気付きました。中を見てみると、概ねファイル名から予想される通りのソースファイルでした。(今までのe2 studioのインストールフォルダを見直してみたところ、以前からあったことが分かりましたが、今まで気付きませんでした。) ただ、一部コメントアウトされているものがあったり、以前に別スレッド『GUNRX用プロジェクトのスマートコンフィグレータのBSPを見ていて気付いた変な移植コード』で話題にしたことと同じ元のコードの意図を理解していない書き換えがあったり、ちょっと惜しいような気もしました。e2 studioインストールフォルダ\internal\projectgen\rx\Generate\CCRXConversion\inc\CCRXmachine.he2 studioインストールフォルダ\internal\projectgen\rx\Generate\CCRXConversion\inc\CCRXmachine.c
こんにちは。NoMaYです。GNURX(というかGCC)のインラインアセンブラは難しいですね。(それでも、ようやく、きっとこれで合っているに違いない、という感覚が湧き上がってくることがあるレベルになって来ましたが、、、) 以前に投稿したGNURXでの今回のCCRXmachine2.hのxchg()関数のインラインアセンブラ記述の件で、何か腑に落ちない感覚があったのですが、しつこく調べていたところ、stackoverflowというサイトに投稿されていた以下のスレッドを見て、やっと直接の原因を理解出来ました(と思う)。そして、GCC本家のドキュメントを見直してみると、確かにそう書いてありました。つまり、GCCは、より良いコードを生成する為、アセンブラ記述部では変数への書き込みがあった時点で変数からの読み出しは全て完了しているものと仮定してコードを生成する、そういう実装になっている、ということでした。(でも、その仮定が正しくない場合もあるので、その動作を変更するアセンブラ記述も出来るようになっていました。)以前の投稿で腑に落ちなかった記述
static __inline__ void xchg(signed long *data1, signed long *data2) __attribute__((always_inline));static __inline__ void xchg(signed long *data1, signed long *data2){/* CC-RX V2.03 MOV.L [R1], R14 XCHG [R2].L, R14 MOV.L R14, [R1] RTS*/ signed long temp; /* = *data1; */ __asm__ volatile ( /* AssemblerTemplate */ "MOV.L [%[R1]], %[R14]\n\t" "XCHG [%[R2]].L, %[R14]\n\t" "MOV.L %[R14], [%[R1]]" : /* OutputOperands */ [R14] "=r" (temp) : /* InputOperands */ [R1] "r" (data1), [R2] "r" (data2) ); /* *data1 = temp; */ return;/* GNURX 2018q1 92 0010 EC 12 MOV.L [r1], r2 ← r2を壊してしまった 93 0012 06 A0 10 22 XCHG [r2].L, r2 94 0016 E3 12 MOV.L r2, [r1] 97 0018 02 rts*/}
そして以下のことが思い浮かんだが、、、● インラインアセンブラ記述部のInputOperandとしてポインタの値だけというのは変だよね。少なくとも以下の何れか1つは一緒に指定されていないと変だよね。(1) OutputOperandにポインタの値を加工した値の出力(2) InputOperandにポインタの値(もしくは加工した値)によるメモリのリード(3) OutputOperandにポインタの値(もしくは加工した値)によるメモリのライト(もしくはリードモデファイライト)●この何れも指定されていないのであれば、ポインタの値は実質使われていない、ということだから壊しても構わないよね。やっと直接の原因を理解出来た(と思う、、、)stackoverflow.com/questions/15819794/when-to-use-earlyclobber-constraint-in-extended-gcc-inline-assemblyGCC本家のドキュメントをにも確かにそう書いてありましたgcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#index-asm-output-operandsgcc.gnu.org/onlinedocs/gcc/Modifiers.html#index-earlyclobber-operandですので、今回のCCRXmachine2.hの手元の作業中のソースでは、xchg()関数は以下の記述に至っています。(なお、以下のOutputOperandsとInputOperandsの制約はAssemblerTemplateの3行に渡っての制約ですので、xchg命令単体としての制約とは異なります。)
#ifndef xchg#define xchg(data1, data2) ccrx_machine_h_xchg(data1, data2)#endifstatic __inline__ void ccrx_machine_h_xchg(signed long *data1, signed long *data2) __attribute__((always_inline));static __inline__ void ccrx_machine_h_xchg(signed long *data1, signed long *data2){/* CC-RX V2.03 MOV.L [R1], R14 XCHG [R2].L, R14 MOV.L R14, [R1] RTS*/ signed long temp; __asm__ volatile ( /* AssemblerTemplate */ "MOV.L [%[R1]], %[R14]" "\n\t" "XCHG [%[R2]].L, %[R14]" "\n\t" "MOV.L %[R14], [%[R1]]" "\n\t" : /* OutputOperands */ [R14] "=&r" (temp), /***/ "+m" (*data1), /***/ "+m" (*data2) : /* InputOperands */ [R1] "r" (data1), [R2] "r" (data2) ); return;/* GNURX 2018q1 92 0010 EC 15 MOV.L [r1], r5 93 0012 06 A0 10 25 XCHG [r2].L, r5 94 0016 E3 15 MOV.L r5, [r1] 97 0018 02 rts*/}
ちなみに、"+m" (*data1)や"+m" (*data2)の制約が無いと、私の前の投稿での__builtin_rx_rmpa()関数で滅茶苦茶なコードが生成された件と同様のトラブルが、複雑なソースにxchg()関数がインライン展開された場合に発生する可能性があると思われます。(同様のトラブルの別の例を挙げれば、変数(or 内蔵周辺)にvolatile宣言を付け忘れた時に、コンパイラの最適化レベルによっては、volatile宣言を忘れた変数(or 内蔵周辺)に対してのリードやライトが省略されていたり思わぬ位置に移動していたりする、ということが挙げられると思います。)