MAEC TOOL NEWS:
MAECT-M3T-CC32R-021201D
M3T-CC32R V.4.00 Release 1
ご使用上のお願い
|
M32Rファミリ用クロスツールキットM3T-CC32R V.4.00 Release 1 の使用上の注意事項を連絡します。
- volatile修飾された領域を複数回参照する場合の注意事項
- 該当製品
M3T-CC32R V.4.00 Release 1
- 内容
構造体メンバまたはポインタが示すvolatile修飾された領域を複数回参照した場合に、volatile修飾が無効になる場合があります。
- 2.1 発生条件
- 以下の条件をすべて満たす場合に発生することがあります。
| (1) | コンパイル時に -O4を含む最適化オプションを指定している(-O4, -O5, -O6, -O7, -Otimeのみ、または-Ospaceのみを指定している)。 |
| (2) | 以下のいずれかの参照をしている。
| (a) | 以下の条件をすべて満たす構造体のメンバ。
(i) 構造体の先頭 (第1) メンバ以外のvolatile修飾されているメンバである。
(ii) (i) のメンバの所属する構造体全体はvolatile修飾されていない。 |
| (b) | オフセットつきポインタが指すvolatile修飾された領域。
例: *(ptr+1) |
| (c) | ポインタの配列で指定するvolatile修飾された領域。
例: ptr[0] ※ ptrがポインタの場合のみ |
|
| (3) | (2)を同一関数中で複数回参照している。 |
| (4) | (3)の複数回参照する間に以下のいずれの処理も存在しない。
(a) (2)の参照領域への書き込み
(b) ポインタを使った任意の領域への書き込み
(c) 任意の関数の呼出し |
- 2.2 発生例
[ソースファイル例1:sample1.c]
------------------------------------------------------------------------
typedef struct {
int a;
volatile int b; /* 発生条件(2)(a)(i) */
} DATA1;
DATA1 data1; /* 発生条件(2)(a)(ii) */
void
foo1(void)
{
int tmp;
tmp = data1.b; /* 発生条件(3),(4) */
if (tmp) {
while (data1.b != 2) /* 発生条件(3),(4) */
;
} else {
while (data1.b != 5) /* 発生条件(3),(4) */
;
}
}
------------------------------------------------------------------------
[ソースファイル例2:sample2.c]
------------------------------------------------------------------------
volatile int data2[100];
volatile int *pdata2 = data2; /* 発生条件(2)(c) */
int
foo2(void)
{
int tmp;
tmp = pdata2[1]; /* 発生条件(2)(c),(3),(4) */
if (tmp) {
tmp = pdata2[1]; /* 発生条件(2)(c),(3),(4) */
}
return tmp;
}
------------------------------------------------------------------------
[CC32Rのコマンド操作例(%はプロンプトを表します)]
------------------------------------------------------------------------
% cc32R -c -O4 sample1.c ; 発生条件(1)
% cc32R -c -O4 sample2.c ; 発生条件(1)
------------------------------------------------------------------------
- 各ソースファイルを上記例でコンパイルすると、sample1.cのdata1.bとsample2.cのpdata2[1]の読み出しを最初の1回しか行わず、以降の読み出しを1回めの読み出し結果に置き換えます。volatile修飾が有効なのでこの動作は正しくありません。
- 回避策
- 以下のいずれかの方法で回避してください。
- (1) volatileな領域へのポインタを介して参照する
[sample1.cの変更例]
------------------------------------------------------------------------
typedef struct {
int a;
volatile int b;
} DATA1;
DATA1 data1;
void
foo1(void)
{
int tmp;
volatile int *ptr = &data1.b; /* data1.b へのポインタを用意 */
tmp = *ptr; /* data1.b を *ptr に置き換える */
if (tmp) {
while (*ptr) /* data1.b を *ptr に置き換える */
;
} else {
while (*ptr) /* data1.b を *ptr に置き換える */
;
}
}
------------------------------------------------------------------------
[sample2.cの変更例]
------------------------------------------------------------------------
volatile int data2[100];
volatile int *pdata2 = data2;
int
foo2(void)
{
int tmp;
volatile int *ptr = &pdata2[1]; /* pdata2[1] へのポインタを用意 */
tmp = *ptr; /* pdata[2] を *ptr に置き換える */
if (tmp) {
tmp = *ptr; /* pdata[2] を *ptr に置き換える */
}
return tmp;
}
------------------------------------------------------------------------
- (2) -O4を含む最適化を抑止する。
※ -O4を含む最適化は、-O5, -O6, -O7, -Otimeのみ、または-Ospaceのみを指定しているときにも行われます。-Otimeまたは-Ospaceを使用する場合は同時に-O0,-O1,-O2,-O3のいずれかを指定すると、最適化を抑止できます。
- (3) 任意のポインタによる代入を挿入する
[sample1.cの変更例]
------------------------------------------------------------------------
typedef struct {
int a;
volatile int b;
} DATA1;
DATA1 data1;
int dummy, *dummyaddr = &dummy; /* 書き換え可能な領域 */
void
foo1(void)
{
int tmp;
int *dummyptr = dummyaddr; /* ポインタを用意 */
tmp = data1.b;
*dummyptr = 0; /* ポインタを使った代入を挿入 */
if (tmp) {
while (data1.b)
;
} else {
while (data1.b)
;
}
}
------------------------------------------------------------------------
[sample2.cの変更例]
------------------------------------------------------------------------
volatile int data2[100];
volatile int *pdata2 = data2;
int dummy, *dummyaddr = &dummy; /* 書き換え可能な領域 */
int
foo2(void)
{
int tmp;
int *dummyptr = dummyaddr; /* ポインタを用意 */
tmp = pdata2[1];
*dummyptr = 0; /* ポインタを使った代入を挿入 */
if (tmp) {
tmp = pdata2[1];
}
return tmp;
}
------------------------------------------------------------------------
- 恒久対策
本内容は、次期バージョンアップの際に改修する予定です。