link もっと前
   2020年 6月 12日 -
      2020年 6月 3日  
link もっと後

link 未来から過去へ表示(*)
link 過去から未来へ表示

link permalink

link 編集する

懐かしいソフトをインストール

はるか昔(2007年 6月 7日の日記参照)に購入したピアノ音源 PMI Boesendorfer 290 を現在使っている PC にインストールしました。

当時の日本代理店はクリプトンでしたが、2008年に違う会社に変わったようです。

それはさておき、ソフトは古くても(13年前!)音源自体はインストールでき、音も正常に鳴ります。Windows の後方互換性は本当に素晴らしいなと思います。しかしアクティベーションだけがどうしてもできなくて困っています。

オンラインでアクティベートできず

Boesendorfer 290 はインストール時にシリアル番号の入力が必要で、インストール後はアクティベーションが必要です。アクティベーションは各 PC 固有の番号と紐付いていて、別の PC にインストールしたときは再アクティベーションが必要となります。面倒くさいですね。

アクティベーションをしない状態で使い続けると、インストール後 5日間に動かなくなってしまいます。


Boesendorfer 290 アクティベート画面

購入当時はアクティベート画面の「REGISTER NOW」を押せば、オンラインでアクティベーションできましたが、現在このボタンを押すとエラーになります。


オンラインのアクティベーション、エラーその 1


オンラインのアクティベーション、エラーその 2

アクティベーション用のサイトの URL が変わったのか、ブラウザの接続警告が出ますし、転送先のサイトでは「そんなページは知らない」って言われます。これはひどい。

オフラインでもアクティベートできず

オンラインがダメならオフラインアクティベーションを試そうと思い「FILL OUT FORM」を押してみましたが、やっぱりダメでした。


オフラインのアクティベーション、エラー

エラーメッセージを見ても Internet browser の何がダメかわかりません。当然、ユーザーとしても対処しようがありません。このソフトを開発した人たちも、まさか 13年後にアクティベーションする奴がいるとは思っていなかったでしょう。

これ以上どうにもならないので、サポートに連絡することにしました。Boesendorfer 290 の販売は Native Instruments 社、開発は EastWest 社とありますが、どこに連絡すれば良いかわかりません。とりあえず販売 Native Instruments 社のサポートに連絡してみようと思います。

[編集者: すずき]
[更新: 2020年 6月 21日 14:51]

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

link 編集する

Kindle Fire の本が消える病

割と昔からですが Kindle Fire がストアで買った本を認識しない(ダウンロードしない、一覧に出てこない)病気が頻発し、買ったはずの本が消えて、非常に困っています。

Kindle Fire がロストした本は、Kindle for PC だとあっさり捕捉できますから(「新しい商品」順に並べると確認しやすい)、Kindle Fire のバグだと思われます。

根本対策は不明ですが、対症療法はいくつかあります。お手軽な順に、

  • 本の一覧を表示、フィルター「すべて」「ダウンロード済み」を何度か切り替える(3割くらい成功)
  • 対象の本のタイトルを検索ウインドウに入れて検索する(8割くらい成功)
  • Kindle ストアで対象の本を探し「ダウンロード」ボタンを押す(9割 9分成功)
  • ファクトリリセット(これでだめなら Kindle Fire のバグ)

Kindle ストアも割と曲者で、複数のダウンロードボタンがある変な仕様2018年 11月 17日の日記参照)です。1回押してダメでも諦めず、他の種類のダウンロードボタンも押してください。どれかが成功すればラッキーです。

最終手段ファクトリリセットには 1度だけお世話になりました。しかし再設定、再ダウンロードにかなり時間を浪費して辛いので、できればもう二度とやりたくありません。

Kindle Fire の困ったところ

Kindle Fire はちょっと変な挙動が多いです。仕様かバグか良くわからないものもあります。

  • 本の表示がずれて読めなくなる(再起動で直る)
  • 本がダウンロードできない病が頻発する(上述)
  • 本の一覧表示が遅い(アップデートで改悪したり、改善したり)
  • 一覧表示の分類がショボい、本が探せない
  • フィルタの「未読」「既読」の数が間違ってる

Kindle のメインであるはずの本の機能さえ、この有様なので、本以外(アプリ、ミュージック、ムービーなど)の機能は一体どうなっていることやら??

メモ: 技術系の話は Facebook から転記しておくことにした。大幅に追記。

[編集者: すずき]
[更新: 2020年 6月 6日 18:42]

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

link 編集する

FSF Copyright Assignment

FSF (Free Software Foundation) の Copyright Assignment にサインしてみました。とりあえず GCC と binutils です。ツールチェーン仲間としては glibc もやっておけば良かったかも??まあいいか。

手続きは特に難しくなく、

  • assign@gnu.org に特定のテンプレート(※)でメールを送る
  • 契約書が添付された PDF が返ってくる
  • 印刷してサイン+日付を書いた後、スキャンして PDF を送る
  • FSF のサイン+日付が入った PDF が送られてくる

これで完了です。


送られてくる契約書の先頭部分

FSF からの返事はそれぞれ数日〜1週間程度、という感じでした。GNU のソフトウェアにパッチを送りたいときは、個人でこの契約を交わす(今回はこっち)か、会社の業務で作成している場合は、会社でこの契約を交わす(こっちのやり方は知らない)必要があります。

FSF がなぜこんな面倒なことをしているのかについては、なぜ FSF は貢献者に著作権の譲渡をお願いしているのか - GNU プロジェクトに書いてあります。過去に訴えられたり何か嫌なことがあったんでしょうね。

テンプレートは Copyright Papers (Information for Maintainers of GNU Software) を見ると GNU のメンテナーに要求してくれと書いてあります。gnulib のリポジトリにも入っていて、私はこのファイルを送ったら OK でした(gnulib の git リポジトリにある request-assign.future

Copyright Assignment を読んでみて感じたこと

FSF の Copyright Assignment にはいろいろ書いてありますが、

契約者の書いたパッチが契約者のものだと保証せよ
これは契約者を雇っている会社が FSF に著作権を主張してくることを防ごうとしている。
業務上作成したパッチを投稿しなければ満たせる。
FSF の敵に対して協力せよ
契約者が上記の項に反した(会社のコードを投稿したなど)ときに要求されます。
FSF が裁判で勝てるような証拠集めに協力せよ。
FSF が万が一、著作権関係の訴えで負けたら「FSF の被った損害を補償せよ」

読んでいると割と怖い内容ですが、会社で書いたコードを投稿しなければ問題はないです。

契約の範囲はソフトウェア毎(GCC, binutils, glibc, などなど)に契約する必要があります。契約の種類は「1回限り(request-assign.changes)」と「今後ずっと(request-assign.future)」があります。ソフトウェアを改善し続ける場合、毎回契約するのは面倒なので「今後ずっと」を選択すると思います。

契約の種類によって FSF に送るメールのテンプレートが異なります。詳細は Copyright Papers (Information for Maintainers of GNU Software) に書いてあります。和訳ないのかなあ、これ。

[編集者: すずき]
[更新: 2020年 6月 6日 16:02]

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

link 編集する

GCC を調べる - その 14-2 - genopinit と expand と pats[].scode

目次: GCC を調べる - まとめリンク

以前(2020年 5月 24日の日記参照)、変数の代入操作を expand で展開する際、代入を分割するか分割しないか、を決める条件の 1つとして、optab_handler() という関数が出てきました。この関数の動作に関わる genopinit というツールの動作を調べます。

前回(2020年 6月 3日の日記参照)は分岐条件に関わる enum optab_tag の生成について調べました。今回はもう少し複雑な pats[].scode の生成について調べます。

pats[].scode って何だ?

突然 pats[].scode と言われても何だかわからないと思います。私もこんなひどい名前の変数、全く覚えられません。復習も兼ねて optab_handler() を見直します。

分岐条件の 1つ optab_handler()(再掲)

// gcc/optabs-query.h

/* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing
   if the target does not have such an insn.  */

inline enum insn_code
optab_handler (optab op, machine_mode mode)
{
  unsigned scode = (op << 16) | mode;  //★★scode の意味はここにある通り
  gcc_assert (op > LAST_CONV_OPTAB);
  return raw_optab_handler (scode);  //★★これ
}


// build_gcc/insn-opinit.c

enum insn_code
raw_optab_handler (unsigned scode)
{
  int i = lookup_handler (scode);  //★★これ
  return (i >= 0 && this_fn_optabs->pat_enable[i]
          ? pats[i].icode : CODE_FOR_nothing);
}

static int
lookup_handler (unsigned scode)
{
  int l = 0, h = ARRAY_SIZE (pats), m;
  while (h > l)
    {
      m = (h + l) / 2;
      if (scode == pats[m].scode)  //★★これ
        return m;
      else if (scode < pats[m].scode)  //★★これ
        h = m;
      else
        l = m + 1;
    }
  return -1;
}


//★★pats[] の定義

struct optab_pat {
  unsigned scode;
  enum insn_code icode;
};

static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = {
  { 0x010405, CODE_FOR_extendqihi2 },
  { 0x010406, CODE_FOR_extendqisi2 },
  { 0x010407, CODE_FOR_extendqidi2 },
  { 0x010505, CODE_FOR_extendhihi2 },

...

  { 0x021c1b, CODE_FOR_truncdfsf2 },  //★★この変な数字(scode)0x021c1b は誰が作るのか?

...

コードから scode の意味、上位 16ビットが optab で、下位 16ビットが machine mode、は理解できると思います。pats には scode が無数に並んでいますが、この数字を誰が作るかというと genopinit です。

optabs と pattern

前に見た optabs の定義は色々ありますが、必ず 2つ以上の引数を取り、1番目が name(mov_optab, trunc_optab など)、2番目が pattern となっており、この 2つは全ての定義に存在します。

optabs の定義と name, pattern

// gcc/optabs.def

OPTAB_CL(trunc_optab, "trunc$b$a2", TRUNCATE, "trunc", gen_trunc_conv_libfunc)
         '-- name      `-- pattern

このうち name は enum optab_tag の変数名として使っていました。その他にも code_to_optab_[] という配列の定義にも使いますが、今はどうでもいいです。前後に文字が付くくらいで、基本的に名前がそのまま使われます。

一方 2番目の pattern(例えば "mov$a", "trunc$b$a2" など)はちょっと変わっています。$a や $b という不思議な文字が入ります。

genopinit と *.md と scode

前回説明したとおり genopinit の入力は gcc/common.md, gcc/config/riscv/riscv.md, build_gcc/insn-conditions.md の 3つの *.md ファイルです(md は machine descriptor の略)。Lisp っぽい記法で、define_insn や define_expand を追加したファイルです。

基本的な genopinit の動作は、

  • *.md を読む
  • optabs.def の pattern とパターンマッチを掛け、pats[].scode を生成
  • ファイルに出力

パターンマッチのコードはこんな感じです。

genopinit パターンマッチ部分

// gcc/gensupport.h

/* Information about an .md define_* rtx.  */
class md_rtx_info {
public:
  /* The rtx itself.  */
  rtx def;

  /* The location of the first line of the rtx.  */
  file_location loc;

  /* The unique number attached to the rtx.  Currently all define_insns,
     define_expands, define_splits, define_peepholes and define_peephole2s
     share the same insn_code index space.  */
  int index;
};


// gcc/genopinit.c

int
main (int argc, const char **argv)
{

...

  if (!init_rtx_reader_args_cb (argc, argv, handle_arg))  //★★ *.md を解析
    return (FATAL_EXIT_CODE);

...

  /* Read the machine description.  */
  md_rtx_info info;
  while (read_md_rtx (&info))  //★★ RTX を 1つずつ取り出す
    switch (GET_CODE (info.def))
      {
      case DEFINE_INSN:    //★★ define_insn, define_expand だけ注目
      case DEFINE_EXPAND:
	gen_insn (&info);  //★★これ
	break;


static void
gen_insn (md_rtx_info *info)
{
  optab_pattern p;
  if (find_optab (&p, XSTR (info->def, 0)))  //★★これ
    patterns.safe_push (p);
}


// gcc/gensupport.c

bool
find_optab (optab_pattern *p, const char *name)
{

...

  /* See if NAME matches one of the patterns we have for the optabs
     we know about.  */
  for (unsigned int pindex = 0; pindex < ARRAY_SIZE (optabs); pindex++)  //★★全ての pattern を試す
    {
      p->m1 = p->m2 = 0;
      if (match_pattern (p, name, optabs[pindex].pattern))  //★★これ
	{
	  p->name = name;
	  p->op = optabs[pindex].op;
	  p->sort_num = (p->op << 16) | (p->m2 << 8) | p->m1;  //★★scode を作る
	  return true;
	}


// gcc/gensupport.h

/* Information about an instruction name that matches an optab pattern.  */
struct optab_pattern
{
  /* The name of the instruction.  */
  const char *name;

  /* The matching optab.  */
  unsigned int op;

  /* The optab modes.  M2 is only significant for conversion optabs;
     it is zero otherwise.  */
  unsigned int m1, m2;

  /* An index that provides a lexicographical sort of (OP, M2, M1).
     Used by genopinit.c.  */
  unsigned int sort_num;
};

申し訳ないですが *.md ファイルの解析関数 init_rtx_reader_args_cb(), read_md_rtx() 辺りは調べる予定がありません。どなたか調べてくれたら嬉しいです。

パターンマッチは name に対して行われ、全ての pattern とマッチするか試します。マッチしなければ match_pattern() は false を返しますから、次の pattern を試します。マッチしたら、結果は optab_pattern *p に格納され、match_patter() が作り出す p->m1, p->m2 という謎の数から scode が生成されます。

なぜ genopinit では sort_num という変数名にしたんでしょうね?scode にすればもう少しわかりやすいのに。

パターンマッチ m1, m2 と scode

パターンマッチのルールと、m1, m2 が何者か?については、文章で説明できる気がしないので、例として name = "truncdfsf2" を見ながら説明したいと思います。マッチする pattern は "trunc$b$a2" です。他の pattern はマッチしません。

genopinit パターンマッチの一例

// gcc/config/riscv/riscv.md

//★★ name の例

(define_insn "truncdfsf2"    ★★名前
  [(set (match_operand:SF     0 "register_operand" "=f")
	(float_truncate:SF
	    (match_operand:DF 1 "register_operand" " f")))]
  "TARGET_DOUBLE_FLOAT"
  "fcvt.s.dt%0,%1"
  [(set_attr "type" "fcvt")
   (set_attr "mode" "SF")])


// gcc/optab.def

//★★ マッチする pattern の定義部分(2番目の引数)

OPTAB_CL(trunc_optab, "trunc$b$a2", TRUNCATE, "trunc", gen_trunc_conv_libfunc)


// gcc/gensupport.c

//★★
//p は結果格納用の変数
//name = "truncdfsf2"
//pat  = "trunc$b$a2"

static bool
match_pattern (optab_pattern *p, const char *name, const char *pat)
{

...
パターンマッチしたときの各変数のダンプ
★★match_pattern() が true を返した後、find_optab() が return true で終了する直前でダンプ

(gdb) p optabs[pindex]

$13 = {
  name = 0x4574b5 "trunc_optab",
  pattern = 0x4574c1 "trunc$b$a2",
  base = 0x4574cc ""trunc"",
  suffix = 0x457478 "'\0'",
  libcall = 0x4574d4 "gen_trunc_conv_libfunc",
  op = 2,
  fcode = TRUNCATE,
  rcode = UNKNOWN,
  kind = 1
}


(gdb) p/x *p

$15 = {
  name = 0x4dd270,
  op = 0x2,
  m1 = 0x1b,
  m2 = 0x1c,
  sort_num = 0x21c1b
}

p は結果格納用の optab_pattern *p

この定義の pattern は 2番目の引数 "trunc$b$a2" です。全部繋がっていてわかりにくいですが、下記の 4つの要素から構成されます。

  • trunc
  • $b: パターンマッチ その 2
  • $a: パターンマッチ その 1
  • 2

このうち $a や $b は machine mode の名前にマッチします。具体的には下記のようになります。

$a, $b パターンマッチの仕組み
name と pat が

  name = "truncdfsf2"
  pat  = "trunc$b$a2"

の場合、

  $b -> df
  $a -> sf

にマッチします。$a, $b のマッチを調べるときは mode_name を先頭から検索(大文字小文字の違いは無視)します。
全モードの名前は mode_name[] という配列に入っています。

  $b は mode_name[28] = "DF" と一致する。
  $a は mode_name[27] = "SF" と一致する。

match_pattern() は一致したモードの番号を m1, m2 に格納します。
つまり optab_pattern の m1, m2 の意味はそれぞれ

  m1: $a がマッチしたモードのインデックス、今回だと 27 = 0x1b (E_SFmode)
  m2: $b がマッチしたモードのインデックス、今回だと 28 = 0x1c (E_DFmode)

結果 scode はこうなります。

  p->sort_num = (p->op << 16) | (p->m2 << 8) | p->m1;
              = (2 << 16) | (28 << 8) | 27;
              = 0x21c1b

// build_gcc/insn-opinit.c

static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = {
...
  { 0x021c1b, CODE_FOR_truncdfsf2 },  //★★この値が生成された

謎の pats[].scode はこんな仕組みで生成されていたのでした。ややこしいですね。

[編集者: すずき]
[更新: 2020年 6月 4日 12:18]

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

link 編集する

GCC を調べる - その 14-1 - genopinit と expand と enum optab_tag

目次: GCC を調べる - まとめリンク

以前(2020年 5月 24日の日記参照)、変数の代入操作を expand で展開する際、代入を分割するか分割しないか、を決める条件の 1つとして、optab_handler() という関数が出てきました。optab_handler() の動作を決める genopinit というツールの動作を調べます。

バイナリは build_gcc/build/genopinit に生成されます(以降 build_gcc は GCC のビルドディレクトリを指すものとします)。実行する際の引数は下記の通りです。

genopinit の使い方(再掲)

# build_gcc/Makefile

s-opinit: $(MD_DEPS) build/genopinit$(build_exeext) insn-conditions.md
	$(RUN_GEN) build/genopinit$(build_exeext) $(md_file) \
	  insn-conditions.md -htmp-opinit.h -ctmp-opinit.c


# ビルドログ

build/genopinit ./gcc/gcc/common.md ./gcc/gcc/config/riscv/riscv.md \
  insn-conditions.md -htmp-opinit.h -ctmp-opinit.c

上記のビルドログでは一時ファイルに出力していますが、最終的には build_gcc/insn-opinit.h, build_gcc/insn-opinit.c の 2つのファイルを生成します。

genopinit と enum optab_tag の生成

前回は optab_handler() にブレークポイントを設定するため、enum optab_tag の値を使いました。この値は genopinit が生成しています。

optab_handler(再掲、前半のみ)

// gcc/optabs-query.h

/* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing
   if the target does not have such an insn.  */

inline enum insn_code
optab_handler (optab op, machine_mode mode)
{
  unsigned scode = (op << 16) | mode;  //★★以前は op = mov_optab, mode = E_V64SImode でブレークを掛けた
  gcc_assert (op > LAST_CONV_OPTAB);
  return raw_optab_handler (scode);  //★★次回以降、調べます
}


// build_gcc/insn-opinit.h

enum optab_tag {
  unknown_optab,
  sext_optab,

...

  mov_optab,  //★★この値のこと

...

};

...

typedef enum optab_tag optab;

これらの値は gensupport.c の optab_def から生成されています。実際に optab_def の中身を定義するのは optabs.def ファイルです。この *.def ファイルは、C 言語で素直に書くと重複、冗長になる情報を簡潔に表すための、いわゆる DSL(Domain Specific Language)だと思われます。

DSL っぽいものを使うとき、下記のような邪悪な include の使い方をします。GCC 凶悪デザインパターンの 1つですね。良い子は真似してはいけません。

optab_handler(再掲)

// gcc/gensupport.c

#define OPTAB_DC(o, p, c)          { #o, p, NS, ZS, NS, o, c, c, 4 },
#define OPTAB_D(o, p)  { #o, p, NS, ZS, NS, o, UNKNOWN, UNKNOWN, 4 },

...

/* An array of all optabs.  Note that the same optab can appear more
   than once, with a different pattern.  */
optab_def optabs[] = {
  { "unknown_optab", NULL, NS, ZS, NS, unknown_optab, UNKNOWN, UNKNOWN, 0 },
#include "optabs.def"  //★★上記のように optabs.def 内で使われるマクロを、都合の良い定義に変えてから include
};


// gcc/optabs.def

OPTAB_DC(mov_optab, "mov$a", SET)  //★★マクロの定義は include される場所によって違うので、展開後の結果は場所による
OPTAB_DC(movstrict_optab, "movstrict$a", STRICT_LOW_PART)
OPTAB_D (movmisalign_optab, "movmisalign$a")

...


// gcc/genopinit.c

int
main (int argc, const char **argv)
{

...

  /* Emit the optab enumeration for the header file.  */
  fprintf (h_file, "enum optab_tag {\n");
  for (i = j = 0; i < n; ++i)
    {
      optabs[i].op = i;
      fprintf (h_file, "  %s,\n", optabs[i].name);  //★★optabs の名前を出力
      if (optabs[i].kind != j)
	last_kind[j++] = i - 1;
    }
  fprintf (h_file, "  FIRST_CONV_OPTAB = %s,\n", optabs[last_kind[0]+1].name);

...

せっかく DSL っぽいものがあるのに、genopinit のようにコード自動生成ツールも混ぜて使うのはどうしてなんでしょう?GCC は理解不能です。

[編集者: すずき]
[更新: 2020年 6月 3日 23:12]

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
   2020年 6月 12日 -
      2020年 6月 3日  
link もっと後

管理用メニュー

link 記事を新規作成

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDF ファイル RSS 1.0
QR コード QR コード

最終更新: 7/12 19:53

カレンダー

<2020>
<<<06>>>
-123456
78910111213
14151617181920
21222324252627
282930----

最近のコメント 5件

  • link 20年06月28日
    すずき 「コメントありがとうございます。私もやって...」
    (更新:07/12 00:53)
  • link 20年06月28日
    匿名 「「階段抜き」「ノンエスカレーター」「効率...」
    (更新:07/11 18:26)
  • link 20年06月29日
    すずき 「うちのマシンは基本速度が取得できてないん...」
    (更新:07/01 11:18)
  • link 20年06月29日
    hdk 「Athlon 5350 (2.05GHz...」
    (更新:06/30 23:55)
  • link 20年05月02日
    すずき 「ちょっと調べたところ、コアが焼けると騒ぎ...」
    (更新:05/08 15:43)

最近の記事 3件

link もっとみる
  • link 20年07月12日
    すずき 「[MAD Tower Tycoon コンプリート] MAD Tow...」
    (更新:07/12 19:53)
  • link 20年07月11日
    すずき 「[STATIONflow コンプリート] STATIONflow ...」
    (更新:07/12 01:01)
  • link 20年07月10日
    すずき 「[MAD Tower Tycoon 楽しい] 最近 Steam で...」
    (更新:07/12 00:56)

こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報