こんにちは。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)のインラインアセンブラは難しいですね。以下のドキュメントを読みながら書いているのですが、(当たり前ですが)書き方を間違えると期待したコードが生成されませんね、、、(悲しいことに、まだ私は何が間違っていて何が正しい書き方なのかを理解出来るレベルに到達していない、、、)6.45.2 Extended Asm - Assembler Instructions with C Expression Operandsgcc.gnu.org/onlinedocs/gcc/Extended-Asm.html今までのコード ⇒ OK
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 */ "XCHG [%[R2]].L, %[R14]" : /* OutputOperands */ [R14] "+r" (temp) : /* InputOperands */ [R2] "r" (data2) ); *data1 = temp; return;/* GNURX 2018q1 91 0010 EC 15 mov.L [r1], r5 95 0012 06 A0 10 25 XCHG [r2].L, r5 99 0016 E3 15 mov.L r5, [r1] 100 0018 02 rts*/}
試しに書き換えてみた ⇒ NG
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*/}
更に書き換えてみた ⇒ OK
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; __asm__ volatile ( /* AssemblerTemplate */ "MOV.L %[mR1], %[R14]\n\t" "XCHG %[mR2].L, %[R14]\n\t" "MOV.L %[R14], %[mR1]" : /* OutputOperands */ [R14] "=r" (temp), [mR1] "+m" (*data1), [mR2] "+m" (*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*/}
ちなみに、まだ試行錯誤中ですが、CC-RXで積和演算を行うrmpab()関数は積和演算命令のレジスタの使い方が特徴的だったせいで苦し紛れにGNURXで以下のように記述してみたのですが、コンパイラの最適化処理の足枷になってしまうのでしょうが、他の関数でも同様に変数に割り当てるレジスタを強制的に指定しておいてから他のコンパイラでインラインアセンブラを使う時と同様の感覚で記述する(たぶん記述出来るのではないかと思う)、というやり方にも心惹かれます。(でも、今回のCCRXmachine2.hではやらないつもりですが、、、)(補 GNURXで%r0のようなレジスタ表記も出来るのですね。GNURX Migration Guide : Inline_Assemblygcc-renesas.com/migration-guides/rx/index.html#Inline_Assembly以下のコードは以下のドキュメントを読みながら書いていました。6.45.5.2 Specifying Registers for Local Variablesgcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html)
static __inline__ long long rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2) __attribute__((always_inline));static __inline__ long long rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2){/* CC-RX V2.03 ARG init = R2:R1 ARG count = R3 ARG addr1 = R4 ARG addr2 = 04H[R0](08H[R0] after push R6) RET R2:R1 PUSH.L R6 MOV.L R1, R14 MOV.L R2, R5 MOV.L 08H[R0], R2 SHAR #1FH, R5, R6 MOV.L R4, R1 MOV.L R14, R4 RMPA.B MOV.L R5, R2 MOV.L R4, R1 RTSD #04H, R6-R6*/ register signed char *r1 __asm__("r1") = addr1; register signed char *r2 __asm__("r2") = addr2; register unsigned long r3 __asm__("r3") = count; register long long r5r4 __asm__("r4") = init; register signed long r6 __asm__("r6") = (signed long)(init >> 63); __asm__ volatile ( /* AssemblerTemplate */ "RMPA.B" : /* OutputOperands */ "+r" (r5r4), "+r" (r6) : /* InputOperands */ "X" (r1), "X" (r2), "X" (r3) ); return r5r4;/* GNURX 2018q1 111 0019 7E A6 push.l r6 113 001b 60 40 sub #4, r0 116 001d EF 25 mov.L r2, r5 117 001f EF 1E mov.L r1, r14 122 0021 EF 41 mov.L r4, r1 125 0023 A8 8A mov.L 12[r0], r2 128 0025 EF E4 mov.L r14, r4 131 0027 FD BF 56 shar #31, r5, r6 134 002a 7F 8C RMPA.B 139 002c EF 41 mov.L r4, r1 141 002e EF 52 mov.L r5, r2 142 0030 3F 66 02 rtsd #8, r6-r6*/}
積和演算命令のレジスタの使い方は以下のようにストリング操作命令同様(というかそれ以上)に特徴的ですね。RXファミリ ユーザーズマニュアル ソフトウェア編www.renesas.com/ja-jp/doc/products/mpumcu/doc/rx_family/r01us0032jj0120_rxsm.pdfなお、GNURX対応のCCRXmachin.cのrmpab()関数は以下のように積和演算命令は使わずに記述されていました。
long long rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2){ long long result = init; unsigned long index; for(index = 0; index < count; index++) { result += addr1[index] * addr2[index]; } return result;}
GNURX の __builtin_rx_xchg() を確認してみましたが
$ cat -n xchgTest.c 1 extern int a, b; 2 3 void hoge(void) 4 { 5 __builtin_rx_xchg(&a, &b); 6 } $ rx-elf-gcc -v Using built-in specs. COLLECT_GCC=C:\Renesas\e2studio\GCC for Renesas RX 4.8.4.201801-GNURX-ELF\rx-elf\rx-elf\bin\rx-elf-gcc.exe COLLECT_LTO_WRAPPER=c:/renesas/e2studio/gcc\ for\ renesas\ rx\ 4.8.4.201801-gnurx-elf/rx-elf/rx-elf/bin/../libexec/gcc/rx-elf/4.8.4.201801-GNURX/lto-wrapper.exe Target: rx-elf Configured with: /builder/AutomatedBuilds/rx/builds/2018q1_RX_RC3/rx/source/gcc/configure --target=rx-elf --host=i586-mingw32msvc --enable-languages=c,c++ --disable-shared --with-newlib --enable-lto --enable-libssp --enable-plugins --enable-gold --disable-libstdcxx-pch --with-pkgversion=GCC_Build_20180316 --prefix=/builder/AutomatedBuilds/rx/builds/2018q1_RX_RC3/rx/rx_win Thread model: single gcc version 4.8.4.201801-GNURX (GCC_Build_20180316) $ rx-elf-gcc -O2 xchgTest.c -S -o - .file "xchgTest.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: mov.L #_a, r2 mov.L [r2], r3 mov.L #_b, r5 mov.L [r5], r4 mov.L r3, [r2] xchg r4, r3 mov.L r4, [r5] rts .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $
ちょっと排他制御には使えない感じですね。
こんにちは。NoMaYです。私の前の投稿のxchg()関数のインラインアセンブラ記述の件は、何か腑に落ちない、という感じがしていたのですが、今朝目が覚めて暫くして、GCCの気持ちとして、ひょっとして以下のようなことなのかな?というのが頭に思い浮かびました。● インラインアセンブラ記述部のInputOperandとしてポインタの値だけというのは変だよね。少なくとも以下の何れか1つは一緒に指定されていないと変だよね。(1) OutputOperandにポインタの値を加工した値の出力(2) InputOperandにポインタの値(もしくは加工した値)によるメモリのリード(3) OutputOperandにポインタの値(もしくは加工した値)によるメモリのライト(もしくはリードモデファイライト)●この何れも指定されていないのであれば、ポインタの値は実質使われていない、ということだから壊しても構わないよね。そこで、以下のように記述してみたところ、意図したコードが生成されました。
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; __asm__ volatile ( /* AssemblerTemplate */ "MOV.L [%[R1]], %[R14]\n\t" "XCHG [%[R2]].L, %[R14]\n\t" "MOV.L %[R14], [%[R1]]" : /* 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*/}
こんにちは。NoMaYです。
fujita nozomu said:つーか、ただの交換も機能しない罠。
static rtxrx_expand_builtin_xchg (tree exp){ rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0)); rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1)); /* if arg2 is a reg than we can safely use the form xchg [Rs].memex, Rd, othewise only xchg Rs, Rd */ if(REG_P(arg2)) { rtx mem1 = gen_rtx_MEM (SImode, arg1); rtx mem2 = gen_rtx_MEM (SImode, arg2); rtx mem1toreg = copy_to_reg(mem1); MEM_VOLATILE_P (mem1) = 1; MEM_VOLATILE_P (mem2) = 1; emit_insn (gen_exchangesi (mem1toreg, mem2)); emit_move_insn(mem1, mem1toreg); } else { rtx mem1 = gen_rtx_MEM (SImode, arg1); rtx mem2 = gen_rtx_MEM (SImode, arg2); rtx mem1toreg = copy_to_reg(mem1); rtx mem2toreg = copy_to_reg(mem2); MEM_VOLATILE_P (mem1) = 1; MEM_VOLATILE_P (mem2) = 1; emit_insn (gen_exchangesi (mem1toreg, mem2toreg)); emit_move_insn(mem1, mem1toreg); emit_move_insn(mem2, mem2toreg); } return NULL_RTX;}
> ひょっとして、後続の最適化処理で命令の順番が入れ替わってしまったのでは?
最適化レベル 0 や 1 でコンパイルすると効率は悪いものゝ交換自体には問題がないっぽいコードを吐くのでそれっぽい感じですね。
$ rx-elf-gcc -O0 xchgTest.c -S -o - .file "xchgTest.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: push.l r6 mov.L r0, r6 mov.L #_a, r5 mov.L [r5], r4 mov.L #_b, r5 mov.L [r5], r5 xchg r5, r4 mov.L #_a, r3 mov.L r4, [r3] mov.L #_b, r4 mov.L r5, [r4] rtsd #4, r6-r6 .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $ rx-elf-gcc -O1 xchgTest.c -S -o - .file "xchgTest.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: mov.L #_a, r3 mov.L [r3], r2 mov.L #_b, r5 mov.L [r5], r4 xchg r4, r2 mov.L r2, [r3] mov.L r4, [r5] rts .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $
fujita nozomu said:ちょっと排他制御には使えない感じですね。
#define bool _Bool#define false 0#define true 1typedef signed char int8_t;typedef unsigned char uint8_t;typedef signed short int16_t;typedef unsigned short uint16_t;typedef signed long int32_t;typedef unsigned long uint32_t;typedef signed long long int64_t;typedef unsigned long long uint64_t;typedef unsigned long size_t;/* By default modules will use global locks found in mcu_locks.c. If the user is using a RTOS and would rather use its locking mechanisms then they can change this macro. NOTE: If '1' is chosen for this macro then the user must also change the next macro 'BSP_CFG_USER_LOCKING_TYPE'. 0 = Use default locking (non-RTOS) 1 = Use user defined locking mechanism. */#define BSP_CFG_USER_LOCKING_ENABLED (0)/* If the user decides to use their own locking mechanism with FIT modules then they will need to redefine the typedef that is used for the locks. If the user is using a RTOS then they would likely redefine the typedef to be a semaphore/mutex type of their RTOS. Use the macro below to set the type that will be used for the locks. NOTE: If BSP_CFG_USER_LOCKING_ENABLED == 0 then this typedef is ignored. NOTE: Do not surround the type with parentheses '(' ')'.*/#define BSP_CFG_USER_LOCKING_TYPE bsp_lock_ttypedef enum { BSP_LOCK_BSC = 0, BSP_LOCK_CAC, BSP_LOCK_CAN0, BSP_LOCK_CAN1, BSP_LOCK_CMT, BSP_LOCK_CMT0, BSP_LOCK_CMT1, BSP_LOCK_CMT2, BSP_LOCK_CMT3, /* 略 */ BSP_LOCK_GLCDC, BSP_LOCK_DRW2D, BSP_NUM_LOCKS //This entry is not a valid lock. It is used for sizing g_bsp_Locks[] array below. Do not touch!} mcu_lock_t;typedef struct{ /* The actual lock. int32_t is used because this is what the xchg() instruction takes as parameters. */ int32_t lock; /* Could add a ID for locking and unlocking. In this could protect against any function being able to unlock. */} bsp_lock_t;BSP_CFG_USER_LOCKING_TYPE g_bsp_Locks[BSP_NUM_LOCKS]; bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){#if BSP_CFG_USER_LOCKING_ENABLED == 0 bool ret = false; /* Variable used in trying to acquire lock. Using the xchg instruction makes this atomic */ int32_t is_locked = true; /* This example uses the RX MCU's atomic xchg() instruction. plock->lock is the lock we are trying to reserve. The way this works is that 'is_locked' gets the value of the plock->lock and plock->lock gets the value of 'is_locked' which we just set to 'true'. Basically this is an atomic 'swap' command. If the lock had not yet been reserved then its value would be 'false' and after the xchg() instruction finished 'is_locked' would have 'false'. If it had already been reserved then 'is_locked' would have 'true' after the xchg() instruction. Since plock->lock was already 'true' and we just set it back to 'true' everything is ok. To see if we reserved the lock we just need to check the value of 'is_locked' after this instruction finishes. */ /* Try to acquire semaphore to obtain lock */ __builtin_rx_xchg((int *)&is_locked, (int *)&plock->lock); /* xchg(&is_locked, &plock->lock); */ /* Check to see if semaphore was successfully taken */ if (is_locked == false) { /* Lock obtained, return success. */ ret = true; } else { /* Lock was not obtained, another task already has it. */ } return ret; #else /* User is going to handle the locking themselves. */ return BSP_CFG_USER_LOCKING_SW_LOCK_FUNCTION(plock);#endif} /* End of function R_BSP_SoftwareLock() */bool R_BSP_HardwareLock (mcu_lock_t const hw_index){#if BSP_CFG_USER_LOCKING_ENABLED == 0 /* Pass actual lock to software lock function. */ return R_BSP_SoftwareLock(&g_bsp_Locks[hw_index]);#else /* User is going to handle the locking themselves. */ return BSP_CFG_USER_LOCKING_HW_LOCK_FUNCTION(hw_index);#endif} /* End of function R_BSP_HardwareLock() */#define CMT_RX_NUM_CHANNELS 4/*static*/ bool cmt_find_channel (uint32_t * channel){ bool channel_found = false; uint32_t i; /* Look for an available channel. */ for (i = 0; i < CMT_RX_NUM_CHANNELS; i++) {#if BSP_CFG_RTOS_USED == 0 // Non-OS#elif BSP_CFG_RTOS_USED == 1 // FreeRTOS if (i == BSP_CFG_RTOS_SYSTEM_TIMER) { /* Found CMT channel is being used for RTOS. */ continue; }#elif BSP_CFG_RTOS_USED == 2 // SEGGER embOS#elif BSP_CFG_RTOS_USED == 3 // Micrium MicroC/OS#elif BSP_CFG_RTOS_USED == 4 // Renesas RI600V4 & RI600PX#endif if (true == R_BSP_HardwareLock((mcu_lock_t)(BSP_LOCK_CMT0 + i))) { /* Channel found. */ *channel = i; channel_found = true; break; } } return channel_found;}
以下のリストの赤字箇所でセマフォのロックに使用出来る命令列が生成されていた
1035 .global _R_BSP_SoftwareLock 1037 _R_BSP_SoftwareLock: 1041 020c 60 40 sub #4, r0 1045 020e F8 06 01 mov.L #1, [r0] 1047 0211 EC 05 mov.L [r0], r5 1048 0213 06 A0 10 15 xchg [r1].L, r5 1049 0217 E3 05 mov.L r5, [r0] 1051 0219 EC 01 mov.L [r0], r1 1054 021b 61 01 cmp #0, r1 1055 021d FC DB 10 sceq.L r1 1057 0220 67 01 rtsd #4 1060 .global _R_BSP_HardwareLock 1062 _R_BSP_HardwareLock: 1066 0222 60 40 sub #4, r0 1072 0224 F8 06 01 mov.L #1, [r0] 1076 0227 6C 21 shll #2, r1 1081 0229 EC 05 mov.L [r0], r5 1085 022b 70 11 00 00 00 00 add #_g_bsp_Locks, r1 1090 0231 06 A0 10 15 xchg [r1].L, r5 1091 0235 E3 05 mov.L r5, [r0] 1093 0237 EC 01 mov.L [r0], r1 1098 0239 61 01 cmp #0, r1 1099 023b FC DB 10 sceq.L r1 1101 023e 67 01 rtsd #4 1104 .global _cmt_find_channel 1106 _cmt_find_channel: 1110 0240 60 40 sub #4, r0 1113 0242 FB 32 00 00 00 00 mov.L #_g_bsp_Locks+20, r3 1115 0248 66 04 mov.L #0, r4 1117 .balign 8,3,4 1123 024a F8 06 01 mov.L #1, [r0] 1125 024d EC 05 mov.L [r0], r5 1126 024f 06 A0 10 35 xchg [r3].L, r5 1127 0253 E3 05 mov.L r5, [r0] 1129 0255 EC 05 mov.L [r0], r5 1130 0257 61 05 cmp #0, r5 1131 0259 19 bne .L67 1137 025a E3 14 mov.L r4, [r1] 1140 025c 66 11 mov #1, r1 1143 025e 5B 11 movu.B r1, r1 1146 0260 67 01 rtsd #4 1150 0262 62 14 add #1, r4 1152 0264 62 43 add #4, r3 1154 0266 61 44 cmp #4, r4 1155 0268 21 E2 bne .L61 1157 026a 66 01 mov #0, r1 1160 026c 5B 11 movu.B r1, r1 1163 026e 67 01 rtsd #4
こんにちは。NoMaYです。すみません。__builtin_rx_xchg()関数の引数を入れ替えたところ、セマフォのロックには使用出来ませんが、メモリオペランドを伴う命令列が生成されていましたので、GNURXのGCCの__builtin_rx_xchg()関数のソースのif節かelse節かは関係無いようですね。すみません。__builtin_rx_xchg()関数の引数を入れ替えてみた
// __builtin_rx_xchg((int *)&is_locked, (int *)&plock->lock); /* xchg(&is_locked, &plock->lock); */ __builtin_rx_xchg((int *)&plock->lock, (int *)&is_locked); /* xchg(&is_locked, &plock->lock); */
セマフォのロックには使用出来ないがメモリオペランドを伴う命令列が生成されていた
4 .global _R_BSP_SoftwareLock 11 0000 60 40 sub #4, r0 15 0002 EF 15 mov.L r1, r5 17 0004 EC 14 mov.L [r1], r4 19 0006 F8 06 01 mov.L #1, [r0] 21 0009 06 A0 10 04 xchg [r0].L, r4 23 000d 66 01 mov.L #0, r1 26 000f E3 54 mov.L r4, [r5] 28 0011 67 01 rtsd #4 31 .global _R_BSP_HardwareLock 33 _R_BSP_HardwareLock: 37 0013 60 40 sub #4, r0 41 0015 6C 21 shll #2, r1 43 0017 70 15 00 00 00 00 add #_g_bsp_Locks, r1, r5 48 001d EC 54 mov.L [r5], r4 50 001f F8 06 01 mov.L #1, [r0] 52 0022 06 A0 10 04 xchg [r0].L, r4 56 0026 66 01 mov.L #0, r1 60 0028 E3 54 mov.L r4, [r5] 64 002a 67 01 rtsd #4 67 .global _cmt_find_channel 69 _cmt_find_channel: 73 002c 60 40 sub #4, r0 76 002e FB 42 00 00 00 00 mov.L #_g_bsp_Locks+20, r4 78 0034 66 05 mov.L #0, r5 80 .balign 8,3,1 86 0036 EC 43 mov.L [r4], r3 88 0038 F8 06 01 mov.L #1, [r0] 90 003b 06 A0 10 03 xchg [r0].L, r3 95 003f 62 15 add #1, r5 101 0041 FD 22 43 mov.L r3, [r4+] 107 0044 61 45 cmp #4, r5 108 0046 21 F0 bne .L9 110 0048 66 01 mov.L #0, r1 112 004a 67 01 rtsd #4
こんにちは。NoMaYです。度々すみません。私が前々回と前回に試したケースは何れもGNURXのGCCの__builtin_rx_xchg()関数のソースのif節に該当していたようです。スタック上の変数のアドレスを&で取得した場合にもif文のREG_P(arg2)は真になるようです。よくよく考えてみれば、R0レジスタ相対になるのですから、そうなって然るべきものでした。今回、以下の4つの場合を試してみて、そのことを理解しました。(1) リエントラント性は脇において試しにis_locked変数をstatic宣言してみたもの
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 static int32_t is_locked = true;略 __builtin_rx_xchg((int *)&is_locked, (int *)&plock->lock);略
(2) 上記(1)で__builtin_rx_xchg()関数の引数を入れ替えたもの
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 static int32_t is_locked = true;略 __builtin_rx_xchg((int *)&plock->lock, (int *)&is_locked);略
(3) 上位関数から渡されたplock変数は脇において試しに&g_bsp_Locks[BSP_LOCK_CMT0 + 0]を書いたもの
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 int32_t is_locked = true;略 __builtin_rx_xchg((int *)&g_bsp_Locks[BSP_LOCK_CMT0 + 0], (int *)&is_locked);略
(4) 上記(3)で__builtin_rx_xchg()関数の引数を入れ替えたもの
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 int32_t is_locked = true;略 __builtin_rx_xchg((int *)&is_locked, (int *)&g_bsp_Locks[BSP_LOCK_CMT0 + 0]);略
結果は以下の通りでした。(1) リエントラント性は脇において試しにis_locked変数をstatic宣言してみたもの
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 static int32_t is_locked = true;略 __builtin_rx_xchg((int *)&is_locked, (int *)&plock->lock);略 4 .global _R_BSP_SoftwareLock 6 _R_BSP_SoftwareLock: 12 0000 FB 52 00 00 00 00 mov.L #_is_locked.1408, r5 13 0006 EC 54 mov.L [r5], r4 14 0008 06 A0 10 14 xchg [r1].L, r4 15 000c E3 54 mov.L r4, [r5] 18 000e EC 51 mov.L [r5], r1 21 0010 61 01 cmp #0, r1 22 0012 FC DB 10 sceq.L r1 23 0015 02 rts
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 static int32_t is_locked = true;略 __builtin_rx_xchg((int *)&plock->lock, (int *)&is_locked);略 4 .global _R_BSP_SoftwareLock 6 _R_BSP_SoftwareLock: 12 0000 EC 14 mov.L [r1], r4 13 0002 FB 52 00 00 00 00 mov.L #_is_locked.1408, r5 14 0008 EC 53 mov.L [r5], r3 15 000a E3 14 mov.L r4, [r1] 16 000c E3 53 mov.L r3, [r5] 19 000e EC 51 mov.L [r5], r1 22 0010 FC 43 34 xchg r3, r4 24 0013 61 01 cmp #0, r1 25 0015 FC DB 10 sceq.L r1 26 0018 02 rts
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 int32_t is_locked = true;略 __builtin_rx_xchg((int *)&g_bsp_Locks[BSP_LOCK_CMT0 + 0], (int *)&is_locked);略 6 _R_BSP_SoftwareLock: 11 0000 60 40 sub #4, r0 15 0002 FB 52 00 00 00 00 mov.L #_g_bsp_Locks+20, r5 16 0008 EC 54 mov.L [r5], r4 18 000a F8 06 01 mov.L #1, [r0] 20 000d 06 A0 10 04 xchg [r0].L, r4 22 0011 66 01 mov.L #0, r1 25 0013 E3 54 mov.L r4, [r5] 27 0015 67 01 rtsd #4
bool R_BSP_SoftwareLock (BSP_CFG_USER_LOCKING_TYPE * const plock){略 int32_t is_locked = true;略 __builtin_rx_xchg((int *)&is_locked, (int *)&g_bsp_Locks[BSP_LOCK_CMT0 + 0]);略 4 .global _R_BSP_SoftwareLock 6 _R_BSP_SoftwareLock: 11 0000 60 40 sub #4, r0 15 0002 F8 06 01 mov.L #1, [r0] 17 0005 EC 03 mov.L [r0], r3 18 0007 FB 52 00 00 00 00 mov.L #_g_bsp_Locks+20, r5 19 000d E3 03 mov.L r3, [r0] 20 000f EC 54 mov.L [r5], r4 22 0011 FC 43 43 xchg r4, r3 23 0014 E3 54 mov.L r4, [r5] 26 0016 EC 01 mov.L [r0], r1 28 0018 61 01 cmp #0, r1 29 001a FC DB 10 sceq.L r1 31 001d 67 01 rtsd #4
こんにちは。NoMaYです。幾つか前の私の投稿でGNURXのGCCの__builtin_rx_xchg()関数のソースについて「複雑難解な最適化処理との兼ね合いでどちらに転ぶか分からない不安があって悩ましい」と書きましたが、1つ例が思い浮かびました。今まで上位側で以下のようにしていたら期待したセマフォのロックに使用出来る命令列が生成されていた
/*static*/ bool cmt_find_channel (uint32_t * channel){ bool channel_found = false; uint32_t i; bool cmt_locked; /* Look for an available channel. */ for (i = 0; i < CMT_RX_NUM_CHANNELS; i++) {#if BSP_CFG_RTOS_USED == 0 // Non-OS#elif BSP_CFG_RTOS_USED == 1 // FreeRTOS if (i == BSP_CFG_RTOS_SYSTEM_TIMER) { /* Found CMT channel is being used for RTOS. */ continue; }#elif BSP_CFG_RTOS_USED == 2 // SEGGER embOS#elif BSP_CFG_RTOS_USED == 3 // Micrium MicroC/OS#elif BSP_CFG_RTOS_USED == 4 // Renesas RI600V4 & RI600PX#endif if (true == R_BSP_HardwareLock((mcu_lock_t)(BSP_LOCK_CMT0 + i))) { /* Channel found. */ *channel = i; channel_found = true; break; } } return channel_found;}
1104 .global _cmt_find_channel 1106 _cmt_find_channel: 1110 0240 60 40 sub #4, r0 1113 0242 FB 32 00 00 00 00 mov.L #_g_bsp_Locks+20, r3 1115 0248 66 04 mov.L #0, r4 1117 .balign 8,3,4 1123 024a F8 06 01 mov.L #1, [r0] 1125 024d EC 05 mov.L [r0], r5 1126 024f 06 A0 10 35 xchg [r3].L, r5 1127 0253 E3 05 mov.L r5, [r0] 1129 0255 EC 05 mov.L [r0], r5 1130 0257 61 05 cmp #0, r5 1131 0259 19 bne .L67 1137 025a E3 14 mov.L r4, [r1] 1140 025c 66 11 mov #1, r1 1143 025e 5B 11 movu.B r1, r1 1146 0260 67 01 rtsd #4 1150 0262 62 14 add #1, r4 1152 0264 62 43 add #4, r3 1154 0266 61 44 cmp #4, r4 1155 0268 21 E2 bne .L61 1157 026a 66 01 mov #0, r1 1160 026c 5B 11 movu.B r1, r1 1163 026e 67 01 rtsd #4
ところが以下のように書き換えたらそのような命令列が生成されなくなってしまった(ただの交換も機能しない)
/*static*/ bool cmt_find_channel (uint32_t * channel){ bool channel_found = false; uint32_t i; bool cmt_locked; /* Look for an available channel. */ for (i = 0; i < CMT_RX_NUM_CHANNELS; i++) {#if BSP_CFG_RTOS_USED == 0 // Non-OS#elif BSP_CFG_RTOS_USED == 1 // FreeRTOS if (i == BSP_CFG_RTOS_SYSTEM_TIMER) { /* Found CMT channel is being used for RTOS. */ continue; }#elif BSP_CFG_RTOS_USED == 2 // SEGGER embOS#elif BSP_CFG_RTOS_USED == 3 // Micrium MicroC/OS#elif BSP_CFG_RTOS_USED == 4 // Renesas RI600V4 & RI600PX#endif //if (true == R_BSP_HardwareLock((mcu_lock_t)(BSP_LOCK_CMT0 + i))) switch (i) { case 0: cmt_locked = R_BSP_HardwareLock((mcu_lock_t)BSP_LOCK_CMT0); break; case 1: cmt_locked = R_BSP_HardwareLock((mcu_lock_t)BSP_LOCK_CMT1); break; case 2: cmt_locked = R_BSP_HardwareLock((mcu_lock_t)BSP_LOCK_CMT2); break; case 3: cmt_locked = R_BSP_HardwareLock((mcu_lock_t)BSP_LOCK_CMT3); break; default: /* never */ cmt_locked = false; } if (true == cmt_locked) { /* Channel found. */ *channel = i; channel_found = true; break; } } return channel_found;}
74 .global _cmt_find_channel 76 _cmt_find_channel: 80 0034 6E 67 pushm r6-r7 82 0036 60 40 sub #4, r0 86 0038 66 05 mov.L #0, r5 91 003a FB 72 00 00 00 00 mov.L #_g_bsp_Locks+28, r7 98 0040 FB F2 00 00 00 00 mov.L #_g_bsp_Locks+32, r15 105 0046 FB E2 00 00 00 00 mov.L #_g_bsp_Locks+24, r14 112 004c FB 22 00 00 00 00 mov.L #_g_bsp_Locks+20, r2 114 .balign 8,3,1 115 .L13: 120 0052 61 25 cmp #2, r5 121 0054 20 6C beq .L7 123 0056 61 35 cmp #3, r5 124 0058 20 51 beq .L8 125 005a 61 15 cmp #1, r5 126 005c 20 2A beq .L9 131 005e F8 06 01 mov.L #1, [r0] 133 0061 EC 04 mov.L [r0], r4 134 0063 EC 23 mov.L [r2], r3 135 0065 E3 04 mov.L r4, [r0] 136 0067 FC 43 34 xchg r3, r4 138 006a EC 04 mov.L [r0], r4 139 006c 61 04 cmp #0, r4 140 006e FC DB 40 sceq.L r4 142 0071 E3 23 mov.L r3, [r2] 144 .balign 8,3,1 145 .L10: 150 0073 5B 44 movu.B r4, r4 151 0075 61 04 cmp #0, r4 152 0077 21 29 bne .L17 154 .balign 8,3,1 155 .L11: 157 0079 62 15 add #1, r5 159 007b 61 45 cmp #4, r5 160 007d 21 D5 bne .L13 162 007f CF 41 mov.B r4, r1 165 0081 5B 11 movu.B r1, r1 167 0083 3F 67 03 rtsd #12, r6-r7 169 .L9: 174 0086 E3 05 mov.L r5, [r0] 176 0088 EC 04 mov.L [r0], r4 177 008a EC E6 mov.L [r14], r6 178 008c E3 04 mov.L r4, [r0] 179 008e FC 43 64 xchg r6, r4 181 0091 EC 04 mov.L [r0], r4 182 0093 61 04 cmp #0, r4 183 0095 FC DB 40 sceq.L r4 185 0098 E3 E6 mov.L r6, [r14] 191 009a 5B 44 movu.B r4, r4 193 009c 61 04 cmp #0, r4 195 009e 20 DB beq .L11 197 .balign 8,3,1 198 .L17: 200 00a0 E3 15 mov.L r5, [r1] 203 00a2 66 11 mov #1, r1 206 00a4 5B 11 movu.B r1, r1 208 00a6 3F 67 03 rtsd #12, r6-r7 210 .L8: 215 00a9 F8 06 01 mov.L #1, [r0] 217 00ac EC 03 mov.L [r0], r3 218 00ae EC F6 mov.L [r15], r6 219 00b0 E3 03 mov.L r3, [r0] 220 00b2 E3 F6 mov.L r6, [r15] 222 00b4 EC 04 mov.L [r0], r4 223 00b6 61 04 cmp #0, r4 224 00b8 FC DB 40 sceq.L r4 227 00bb FC 43 63 xchg r6, r3 232 00be 2E B5 bra .L10 234 .L7: 239 00c0 F8 06 01 mov.L #1, [r0] 241 00c3 EC 04 mov.L [r0], r4 242 00c5 EC 76 mov.L [r7], r6 243 00c7 E3 04 mov.L r4, [r0] 244 00c9 FC 43 64 xchg r6, r4 246 00cc EC 04 mov.L [r0], r4 247 00ce 61 04 cmp #0, r4 248 00d0 FC DB 40 sceq.L r4 250 00d3 E3 76 mov.L r6, [r7] 256 00d5 2E 9E bra .L10