PDF形式、211kバイト

SH C/C++コンパイラ Ver.5.1C 制限事項
1. float 型積和演算のオブジェクト不正
現象
下例の C ソースを-cpu=sh4,-op=0 でコンパイルすると不正なオブジェクトが生成される。
[例]
void ShcNG(float* op, float dp, float tbl) {
float sum;
sum = dp * tbl;
sum += dp * tbl;
*op = sum;
}
[出力コード]
4: sum = dp * tbl;
MOV
#4,R0
FMOV.S
@(R0,R15),FR3
MOV
#8,R0
FMOV.S
@(R0,R15),FR2
FMUL
FR3,FR2
FMOV.S
FR2,@R15
5: sum += dp * tbl;
FMOV.S
FR3,FR0
MOV
#8,R0
FMOV.S
@(R0,R15),FR1
FMOV.S
@R15,FR3
FMAC
FR0,FR1,FR3
FMOV.S
FR3,@R15
6: *op = sum;
MOV.L
@(12,R15),R3
FMOV.S
FR2,@R3
<-- 変数 sum と FR2 が同一値関係となる。
<-- 積和演算の結果が FR3 に載る。
<-- 変数 sum の値が書き変わる。
<-- 変数 sum の参照を行う時、
FR2 をそのまま使用している。
5 行目の積和演算で sum の値は
書き変わっているので、
4 行目で割付いたレジスタ FR2
はそのまま使用できない。
発生条件
以下の条件を全て満たす場合発生する。
(1) -cpu=sh4/sh3e 指定時
(2) float 型積和演算あり。その式の形式は、a+=b*c(複合代入)である。
(3) (2)の積和演算の前に、変数 a への設定式がある。
(4) (2)の積和演算の後に、変数 a の参照式がある。
回避方法
以下のいずれかの方法で回避してください。
(1) -cpu=sh3 以下のオプションを指定する。
(2) float 型積和演算式(a+=b*c)を乗算の部分と和算の部分に分割して行う。
影響システム
SHC コンパイラ V4.0 以降
2. -cpu=sh4 指定時のコード不正
現象
下例の C ソースを、-cpu=sh4,-fpu=single でコンパイルすると、オブジェクト不正となる。
[例]
typedef struct {
float f1;
float f2;
} tagSample;
static tagSample Sample;
float Foo1(void *pv, int offset) {
return 0.0f;
}
float Foo2(void *pv) {
float f;
f = -Foo1(pv, 0) + (Sample.f1 * 60) * (Sample.f2 - 0.5f);
return f;
}
[出力コード]
00000004
00000004
00000006
00000008
0000000A
0000000C
0000000E
00000010
00000012
00000014
00000016
00000018
0000001A
0000001C
0000001E
00000020
00000022
00000024
00000026
00000026
00000028
0000002C
00000030
00000034
4F22
BFFB
E500
D308
C706
F308
C708
F238
D206
F230
F04D
F128
4F26
F008
F122
000B
F01E
_Foo2:
STS.L
BSR
MOV
MOV.L
MOVA
FMOV.S
MOVA
FMOV.S
MOV.L
FADD
FNEG
FMOV.S
LDS.L
FMOV.S
FMUL
RTS
FMAC
L244:
00000002
RES.W 1
BF000000
.DATA.L
-00000004>
.DATA.L
-00000000>
.DATA.L
42700000
.DATA.L
;function: Foo2
;frame size=4
PR,@-R15
_Foo1
#0,R5
L244+6,R3
L244+2,R0
@R0,FR3
L244+14,R0
@R3,FR2
L244+10,R2
FR3,FR2
FR0
@R2,FR1
@R15+,PR
@R0,FR0
FR2,FR1
;H'00000004+L232
;L232
;-Fool(pw,0)を FR0 に設定
;FR0 の値を破壊
FR0,FR1,FR0
H'BF000000
H'00000004+L232
L232
H'42700000
発生条件
以下の条件を全て満たす場合発生する。
(1) -cpu=sh4 指定時、かつ、FMAC 展開対象となる式がある。
(2) FMAC 対象式の各オペランド評価時、FR0 が固定で割り付けられるオペランド以外で FR0 が割り付け
られた時。
(3) (1),(2)を満たし、かつ、FR0 のデスティネーション先の候補として、FR1~FR3 が不可で FR0 のみ
OK の状態になっている時。
回避方法
FMAC 対象式を以下のように分割して記述してください。
【変更前】
f = -Foo1(pv, 0) + (Sample.f1 * 60) * (Sample.f2 - 0.5f);
【変更後】
f = -Foo1(pv, 0);
f += (Sample.f1 * 60) * (Sample.f2 - 0.5f);
影響システム
SHC/C++コンパイラ V5.1 以降
3. ライブラリ関数 div,ldiv 関数の MAC レジスタ破壊
現象
標準ライブラリ関数 div および ldiv において、MAC レジスタを退避せずに使用しているため、値を破壊
する。
発生条件
以下の条件を全て満たす場合発生する。
(1) 標準ライブラリ関数 div または ldiv を使用している。
(2) SH1 以外を使用している。
(3) -mac=0 オプションは使用していない(デフォルトは-mac=1)
。
(4) (1)の関数呼び出しより上位側のルーチンにアセンブリソースでルーチンを記述している。
(5) (4)の関数で、(1)へ至る関数呼び出しをまたいで MAC レジスタを使用している。
(6) (4)から(1)に至る関数呼び出し上に、MAC レジスタを退避/回復する関数が1つもない。(各関数内
で MUL または MAC 命令を使っていない)
回避方法
ライブラリ関数 div および ldiv は、SH1 用のものを使用してください。
影響システム
SHC/C++コンパイラ V5.1 以降
4. sinf(2π×7/4)で結果不正
現象
sinf(2π×7/4)の結果が-1 となるべきところ 0 となる。
発生条件
以下の条件のいずれかを満たす場合発生する。
(1) -cpu=sh4 で、sin(),cos()のパラメタがπ/4 の倍数に近い時。
(2) -cpu={sh2e|sh3e|sh4}で、sinf(),cosf()のパラメタがπ/4 の倍数に近い時。
回避方法
次のライブラリアップデートプログラムをダウンロードして、lib ディレクトリに置き実行してくださ
い。
UNIX 版をご使用の場合は、PC 上にライブラリ一式を転送し、読み取り専用の属性を解除後、本プログ
ラムを実行してください。
アップデートプログラム (exe 形式、1.25Mバイト)
http://www.hitachi-ul.co.jp/system/XSOFT/news/data/shcv5lib.exe
影響システム
SHC/C++コンパイラ V5.1A 以降
5. ビットフィールドメンバに対する複合剰余演算子のオブジェクト不正
現象
下例の C ソースで、最適化無しでコンパイルすると、ビットフィールドメンバに対する複合剰余演算が
オブジェクト不正になる。
[例]
#include <stdio.h>
#define CH(a,b)(a==b) ? printf("ok (%d,%d)\n",a,b) : printf("ng (%d,%d)\n",a,b);
void main()
{
struct tag {
unsigned int b1:7;
unsigned int b2:7;
signed int b3:7;
signed int b4:7;
} s = {3,4,5,6};
int x = 3;
s.b3 %= 2;
CH(s.b4,0);
}
[出力コード]
;File bug.c ,Line 11
;expression statement
MOV
R15,R2
ADD
#4,R2
MOV.W L286,R1
;H'0E07
MOV.L L286+8,R3
;__bfxls
JSR
@R3
NOP
MOV.L @R2,R0
;不要な転送命令が出ているため s.b3 の値を破壊している
CMP/PZ R0
BF
L282
AND
#1,R0
BRA
L283
NOP
L282:
NOT
R0,R0
ADD
#1,R0
AND
#1,R0
NOT
R0,R0
ADD
#1,R0
L283:
MOV.W L286,R1
;H'0E07
MOV.L L286+12,R3 ;__bfsls
JSR
@R3
NOP
発生条件
以下の条件を全て満たす場合発生する。
(1) 最適化無し(-op=0)でコンパイルする。
(2) 複合剰余演算子があり、左辺は signed のビットフィールドメンバ、右辺は 2n(< 127)の定数である。
回避方法
複合剰余演算を、OP1 %= OP2 -> OP1 = OP1 % OP2 に変更してください。
影響システム
SHC/C++コンパイラ V5.1 以降
6. ループ判定式のオブジェクト不正
現象
下例の C ソースをコンパイルするとループ判定式の置き換えを行い、オブジェクト不正になる。
[例]
unsigned int x;
int func()
{
int i;
for (i = 15; i >= 0; --i) {
x = (((i * 16) + 15) << 24);
}
return (x);
}
↓
unsigned int x;
int func()
{
int i;
for (T1 = 0xff000000; T1 >= 0x0f000000; ) {
x = T1;
T1 = T1 + 0xf0000000;
/* 初期値は signed 型なのでオーバフローする */
}
return (x);
}
発生条件
以下の条件を全て満たす場合発生する。
(1) 帰納変数削除対象のループがある。
(2) (1)の帰納変数がポストインクリメント/デクリメント化しない。
(3) 帰納変数の初期値がオーバーフローしている。
(4) 基本帰納変数が signed 型である。
回避方法
以下のいずれかの方法で回避してください。
(1) 非最適化オプションでコンパイルする。
(2) 定数を unsigned 型に cast する。
影響システム
SHC コンパイラ V3.0~V3.0G および V5.1 以降
7. static メンバをもつクラス内メンバの境界調整数不正
現象
下例で、A::a の境界調整が不正に 1 になる。
[例]
class A {
static char c;
static A a[1];
long l;
// 非 static メンバ l より前に記述
};
char A::c;
A A::a[1];
// 境界調整が 1 になる(正しくは 4)
発生条件
以下の条件を全て満たす場合発生する。
(1) char 型の static クラスメンバが 1 番目に存在する。
(2) (1)の次に自分自身と同じクラス型を持つ static クラスメンバを宣言する。
(3) (2)の次に(1)とは境界調整が増える方向で異なるクラスメンバを宣言する。
回避方法
char 型の static クラスメンバを先頭に記述しないでください。
影響システム
SHC/C++コンパイラ V5.1 以降
8. 仮想関数呼び出し時の this ポインタ不正
現象
下例で、仮想関数の呼び出し時の this ポインタのオフセットが不正になる。
[例]
#include <stdio.h>
class A {
public:
virtual void f() = 0;
};
class B : public A {
public:
int b;
void f() {printf("b = %d\n", b);}
B(int ii = 0) : b(ii) { }
};
class C1 : public B {
public:
C1(int ii = 0) : B(ii) { }
};
class C2 : public B {
public:
C2(int ii = 0) : B(ii) { }
};
class D : public C1, public C2 {
public:
D() : C1(1), C2(2) { }
};
D dd;
main()
{
C2* cp = &dd;
cp->f();
}
// b = 1 となってしまう
// this ポインタが C2 でなく C1 を指している
発生条件
以下の条件を全て満たす場合発生する。
(1) 3 段の単一継承をもつクラス(A - B - C1, A - B - C2)を多重継承で持つ(クラス D)。
(2) 最基底クラス A の仮想関数 f を宣言、次派生クラス B に同仮想関数 f を持つ。
(3) クラス B の仮想関数 f でクラス B のメンバにアクセスする。
(4) D から 2 番目の多重継承クラス C2 のポインタを抽出して仮想関数 f をコールする。*C2 の this ポ
インタが正しく得られない。
回避方法
コールしている仮想関数を持つクラスの派生クラスに同一名の仮想関数を用意して、そこから規定の仮
想関数をコールする処理を追加してください。上記の例に対する回避方法例を示します。
[例]
class C2 : public B {
public:
C2(int ii = 0) : B(ii) { }
virtual void f() {B::f();}
// 追加。中で目的のクラスメンバをコールする。
};
影響システム
SHC/C++コンパイラ V5.1 以降
9. ||の右辺の一時オブジェクトに対するデストラクタコール不正
現象
論理和演算の右辺に一時オブジェクトを利用する式を記述した場合、右辺側の評価の有無に関わらず、
右辺の一時オブジェクトに対するデストラクタをコールしてしまう。
[例]
#include <stdio.h>
class A {
public:
A(){printf("A::A()\n");}
~A(){printf("A::~A()\n");}
int size(){return 1;}
};
extern A k();
void f(int n, int ch)
{
if(1 || k.size() > 0) {
// 論理和の左辺が真なので右辺は実行されない
}
// ここで A の一時オブジェクトのデストラクタをコールしてしまう
}
発生条件
論理和演算の右辺に一時オブジェクトを利用する式を記述したときに発生する。
回避方法
一時オブジェクトを生成する式を論理演算式の右辺には記述しないでください。必ず評価される左辺ま
たは論理式の前に記述してください。
影響システム
SHC/C++コンパイラ V5.1 以降
10. 基底クラスの関数メンバへのポインタ初期設定時の内部エラー(4099)
現象
下例をコンパイルすると、内部エラー(4099)となる。
[例]
class parent {
public:
void parent_func();
};
typedef void (parent::*class_func_ptr)();
class child : public parent {
void child_func();
};
class_func_ptr func_ptr = (class_func_ptr)&child::child_func;
発生条件
以下の条件を全て満たす場合発生する。
(1) 派生クラスの関数メンバへのポインタ定数を、基底クラスの関数メンバへのポインタに初期設定す
る。
(2) 初期値には派生型から基底型へ変換するキャストを入れる。
回避方法
型の合うメンバへのポインタ変数に一時代入して、変数を初期値として利用してください。
[例]
void (child::*temp)() = &child::child_func;
class_func_ptr func_ptr = (class_func_ptr)temp;
影響システム
SHC/C++コンパイラ V5.1 以降
11. リンク時の 3110 エラー(内部エラー849 または 909)
現象
optlnksh 使用時、内部エラー849(最適化有り時)または 909(最適化無し時)が発生する。
発生条件
rom オプションで指定されたセクションの rom 側セクションと ram 側セクションの align が異なるとき
に発生する。
[例]
セクション名 ファイル名 align
A
B
file1
16
file2
16
file3
16
file1
4
セクション B はセクション制御命令だけ宣言(サイズは 0)
.SECTION B, CODE, ALIGN=4
回避方法
rom オプションで指定した rom 側セクションと、ram 側セクションの align を同一にしてください。
[例]
file1 ファイル内の B セクションに対し、align=16 とする。
.SECTION B, CODE, ALIGN=16
影響システム
SHC/C++コンパイラ V5.1 以降
(c) Hitachi ULSI Systems Co., Ltd. 1995,2014. All rights reserved.