コグノスケ


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

link もっと前
2021年3月28日 >>> 2021年3月15日
link もっと後

2021年3月26日

たかいところこわい

3階で思い出したんですが、私は高所恐怖症らしく、背丈の2〜3倍くらいの高さから下を見ると、動悸がして手から変な汗が出ます。

崖、高い吊り橋など、誰でも怖いところは当然怖いんですけど、他の人が怖くないのに、私だけ怖がっている(=理解してもらえない)恐怖スポットとして、

  • 歩道橋
  • 地面が見える階段(踏み板が網やガラスなどのタイプ)
  • 向こうが見える階段(蹴り込み板がないタイプ、例えばこれの「デザイン階段」みたいなやつ)
  • 2階以上で、足下までガラスの窓
  • 2階以上で、向こうが見える柵(※)

(※)自分の背の半分以下の柵、高さがあっても頭が通るくらいの隙間が空いてる柵は怖いです。


階段の板の名前


私が怖いと感じるタイプの階段(パナソニックのサイトから引用)

何が怖いの?と聞かれますが、説明が難しいです。強いて言えば「一歩踏み出したら隙間に吸い込まれそうな恐怖感」でしょうか。隙間から落ちることはないと理解していても、それでも怖いから不思議です。

観光地の「景観スポット」はたいてい恐怖スポットです。さらに良くないことに、周りの人は私が冗談を言ってるように聞こえるようで、ふざけて段差側に押されたりします。本当に恐怖です。勘弁して……。

いろいろある恐怖症

Facebookではいくつかコメントいただいて、興味深かったです。高いところが怖いというのは割と普遍的ですが、怖さの感じるポイントや、感じ方は人それぞれです。

閉所恐怖症なんてのも教えてもらいました。そういうのもあるのか。この年になるとどこかに閉じ込められるという経験をすることはほぼないので、自分が閉所恐怖症なのかどうかすらわからないですね。

メモ: 技術系の話はFacebookから転記しておくことにした。階段の板の名前の図を追加。

編集者:すずき(2021/03/27 12:10)

コメント一覧

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



2021年3月25日

3階に住んで20年

実家を出て20年が経ちました。振り返ると、9割「3階に住んで」います。自分の意志で借りた部屋に限れば、全て3階です。住所の遍歴はこんな感じ。

  • 大学の寮: 113号室(4階建て)1年
  • つくば: 308号室(3階建て)6年
  • 会社の寮: 2階?(10階建て)1年
  • 大阪: 301号室(4階建て)10年
  • 東京: 306号室(5階建て)2年

こう書くと、3階に恨みでもあるか、憑りついている地縛霊みたいですが、私は人間です。さておき真面目な話、1階の部屋と3階の部屋(2〜5階もほぼ同条件)を比べ下記の点が気に入っています。

  • 明るい
  • 外から部屋が見えない
  • 最悪、階段で生活できる(災害時など)

こちらから不動産屋に「3階がいい」と1度も言ったことはないので、1度くらい4階や5階と巡り合っても不思議はなかったはずですが、結局ずっと3階でした。謎の縁ですね。

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

編集者:すずき(2021/03/27 11:16)

コメント一覧

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




2021年3月18日

こっそり下がっている椅子

人によると思うんですけど、私は机に対して椅子の高さが低すぎると、肘で体重を支えるようになり異常に肩が痛くなります。肩が痛いのは嫌なので椅子の高さを調節していたはずなのに、なぜか最近また肩が痛くなってきました。

これはおかしいと思って椅子の高さを確認すると、いつの間にか下がっています。高さ調整機能がヘタっているのか?時間とともにジワジワ下がっているようです。

なんてことするんだ、やめてー。

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

編集者:すずき(2022/04/06 18:53)

コメント一覧

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



2021年3月15日

GCCを調べる - memmoveのfoldingその3

目次: GCC

前回はmemmove() をmemcpy() に置き換える条件をチェックしているコードを紹介しました。より詳細に見ていきたいと思います。ここまで細かい話になると、もはや自分以外の誰得なのか全くわかりませんけど、そんなことを気にしてはいけません。

volatileの有無で何が変わるか?

前回紹介したチェック箇所のうちvolatileの有無で動きが変わるのは、下記のoperand_equal_p() です。

memmove置き換え前のチェック箇所

// gcc/gcc/gimple-fold.c

	      if (SSA_VAR_P (src_base)
		  && SSA_VAR_P (dest_base))    //★★この条件が成立する
		{
                  //★★volatileがあるとoperand_equal_p() がfalseを返し、
                  //★★memmoveがmemcpyに置き換えられてしまう
		  if (operand_equal_p (src_base, dest_base, 0)
		      && ranges_maybe_overlap_p (src_offset, maxsize,
						 dest_offset, maxsize))
		    return false;    //★★チェック1箇所目
		}


// gcc/gcc/fold-const.c

/* Return nonzero if two operands (typically of the same tree node)
   are necessarily equal. FLAGS modifies behavior as follows:

   If OEP_ONLY_CONST is set, only return nonzero for constants.
   This function tests whether the operands are indistinguishable;
   it does not test whether they are equal using C's == operation.
   The distinction is important for IEEE floating point, because
   (1) -0.0 and 0.0 are distinguishable, but -0.0==0.0, and
   (2) two NaNs may be indistinguishable, but NaN!=NaN.

   If OEP_ONLY_CONST is unset, a VAR_DECL is considered equal to itself
   even though it may hold multiple values during a function.
   This is because a GCC tree node guarantees that nothing else is
   executed between the evaluation of its "operands" (which may often
   be evaluated in arbitrary order).  Hence if the operands themselves
   don't side-effect, the VAR_DECLs, PARM_DECLs etc... must hold the
   same value in each operand/subexpression.  Hence leaving OEP_ONLY_CONST
   unset means assuming isochronic (or instantaneous) tree equivalence.
   Unless comparing arbitrary expression trees, such as from different
   statements, this flag can usually be left unset.

   If OEP_PURE_SAME is set, then pure functions with identical arguments
   are considered the same.  It is used when the caller has other ways
   to ensure that global memory is unchanged in between.

   If OEP_ADDRESS_OF is set, we are actually comparing addresses of objects,
   not values of expressions.

   If OEP_LEXICOGRAPHIC is set, then also handle expressions with side-effects
   such as MODIFY_EXPR, RETURN_EXPR, as well as STATEMENT_LISTs.

   If OEP_BITWISE is set, then require the values to be bitwise identical
   rather than simply numerically equal.  Do not take advantage of things
   like math-related flags or undefined behavior; only return true for
   values that are provably bitwise identical in all circumstances.

   Unless OEP_MATCH_SIDE_EFFECTS is set, the function returns false on
   any operand with side effect.  This is unnecesarily conservative in the
   case we know that arg0 and arg1 are in disjoint code paths (such as in
   ?: operator).  In addition OEP_MATCH_SIDE_EFFECTS is used when comparing
   addresses with TREE_CONSTANT flag set so we know that &var == &var
   even if var is volatile.  */

bool
operand_compare::operand_equal_p (const_tree arg0, const_tree arg1,
				  unsigned int flags)
{
  bool r;
  if (verify_hash_value (arg0, arg1, flags, &r))
    return r;

...

  /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal.
     We don't care about side effects in that case because the SAVE_EXPR
     takes care of that for us. In all other cases, two expressions are
     equal if they have no side effects.  If we have two identical
     expressions with side effects that should be treated the same due
     to the only side effects being identical SAVE_EXPR's, that will
     be detected in the recursive calls below.
     If we are taking an invariant address of two identical objects
     they are necessarily equal as well.  */
  if (arg0 == arg1 && ! (flags & OEP_ONLY_CONST)
      && (TREE_CODE (arg0) == SAVE_EXPR
	  || (flags & OEP_MATCH_SIDE_EFFECTS)
	  || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1))))
    return true;  //★★volatileがないときは、このチェックに引っかかるが、volatileがあると引っかからない

...

変化する箇所を見つけましたので、条件を全部バラしてvolatileの有無でどの条件が変化するか調べます。GCCはこういう訳のわからないif文を連発してくるため、非常に解析が大変です……。

volatileの有無で変化する条件を調べる

// ★★下記のように条件を全て展開して差分を調べる

int a, b, c, d, e, f, g;

a = arg0 == arg1;
b = ! (flags & OEP_ONLY_CONST);
c = TREE_CODE (arg0) == SAVE_EXPR;
d = flags & OEP_MATCH_SIDE_EFFECTS;
e = ! TREE_SIDE_EFFECTS (arg0);    //★★この条件が変わる
f = ! TREE_SIDE_EFFECTS (arg1);    //★★この条件が変わる
g = ppa && ppb && (ppc || ppd || (ppe && ppf));

/*
 * volatileなし
 *   (a, b, c, d, e, f, g)
 *   (1, 1, 0, 0, 1, 1, 1)
 * volatileあり
 *   (a, b, c, d, e, f, g)
 *   (1, 1, 0, 0, 0, 0, 0)
 *
 * volatileありのときはside_effects_flagが1になる。
 */


// gcc/gcc/tree.h

/* In any expression, decl, or constant, nonzero means it has side effects or
   reevaluation of the whole expression could produce a different value.
   This is set if any subexpression is a function call, a side effect or a
   reference to a volatile variable.  In a ..._DECL, this is set only if the
   declaration said `volatile'.  This will never be set for a constant.  */
#define TREE_SIDE_EFFECTS(NODE) \
  (NON_TYPE_CHECK (NODE)->base.side_effects_flag)


//★★参考: side_effects_flagを設定する場所
// gcc/gcc/c-family/c-common.c

/* Apply the TYPE_QUALS to the new DECL.  */

void
c_apply_type_quals_to_decl (int type_quals, tree decl)
{
  tree type = TREE_TYPE (decl);

  if (type == error_mark_node)
    return;

  if ((type_quals & TYPE_QUAL_CONST)
      || (type && TREE_CODE (type) == REFERENCE_TYPE))
    /* We used to check TYPE_NEEDS_CONSTRUCTING here, but now a constexpr
       constructor can produce constant init, so rely on cp_finish_decl to
       clear TREE_READONLY if the variable has non-constant init.  */
    TREE_READONLY (decl) = 1;
  if (type_quals & TYPE_QUAL_VOLATILE)
    {
      TREE_SIDE_EFFECTS (decl) = 1;    //★★ここで設定する
      TREE_THIS_VOLATILE (decl) = 1;
    }
  if (type_quals & TYPE_QUAL_RESTRICT)
    {
      while (type && TREE_CODE (type) == ARRAY_TYPE)
	/* Allow 'restrict' on arrays of pointers.
	   FIXME currently we just ignore it.  */
	type = TREE_TYPE (type);
      if (!type
	  || !POINTER_TYPE_P (type)
	  || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type)))
	error ("invalid use of %<restrict%>");
    }
}

もしsrcやdestにvolatile修飾子が付いていると、side_effects_flagがセットされます。このフラグがセットされていると、GCCはアドレスをチェックすることなく、問答無用でsrcとdestは「等しくない」と判断します。その結果srcとdestは重なっていないことになって、memmove() をmemcpy() に置き換える最適化が働きます。

正直な感想としてはGCCバグってるだろ……と思いますが、volatile変数はいつ書き換わってもおかしくないので、memmove() をmemcpy() に置き換えて、動作がおかしくなっても規格違反にはならない?うーん、良くわかりませんね。

ちなみにClang/LLVMはこのような最適化は行いません。memmove() はmemmove() の呼び出しのままです。

x86_64環境の事情

さらに厄介なことにx86_64のglibcはmemmove() を呼ぶべき場面でmemcpy() を呼んでも、正常に動いてしまいます。検証用のプログラムを下記のように変えます。

重複したメモリ領域にmemcpy() するプログラム

#include <stdio.h>
#include <string.h>

#define PRE "AB"
#define STR "0123456789abcdefg"
#define NOP __asm__ volatile("nop;")

int main(int argc, char *argv[])
{
	volatile char s[] = PRE STR;
	char *p = (char *)s;
	size_t sz_pre = strlen(PRE);
	size_t sz = strlen(p) - sz_pre + 1;

	NOP;
	memcpy(p, p + sz_pre, sz);
	NOP; NOP;

	if (strcmp(p, STR) == 0) {
		printf("  OK: %s\n", p);
	} else {
		printf("  NG: %s\n", p);
	}
}

オプション -fno-builtinを指定すると、GCCがmemcpy() をアセンブラへ展開しようとする最適化を抑制することができます。

重複したメモリ領域にmemcpy() するプログラムの実行結果
$ gcc -O2 -Wall -g test.c -fno-builtin

$ objdump -drS a.out

...

        NOP;
    10b7:       90                      nop
        size_t sz = strlen(p) - sz_pre + 1;
    10b8:       48 83 c2 01             add    $0x1,%rdx
        memcpy(p, p + sz_pre, sz);
    10bc:       48 8d 74 1d 00          lea    0x0(%rbp,%rbx,1),%rsi
    10c1:       48 89 ef                mov    %rbp,%rdi
        size_t sz = strlen(p) - sz_pre + 1;
    10c4:       48 29 da                sub    %rbx,%rdx
        memcpy(p, p + sz_pre, sz);
    10c7:       e8 94 ff ff ff          callq  1060 <memcpy@plt>    ;★★memcpyを呼んでいる
        NOP; NOP;
    10cc:       90                      nop
    10cd:       90                      nop


$ ./a.out

  OK: 0123456789abcdefg

この動作でもC言語仕様に違反するわけではありません。しかしGCCが間違ってmemmove() をmemcpy() に置き換えるようなバグがあったときに、意図せず隠蔽してしまいます。ありがたいような、ありがたくないような実装ですね。

編集者:すずき(2023/09/24 11:53)

コメント一覧

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



link もっと前
2021年3月28日 >>> 2021年3月15日
link もっと後

管理用メニュー

link 記事を新規作成

<2021>
<<<03>>>
-123456
78910111213
14151617181920
21222324252627
28293031---

最近のコメント5件

  • link 24年4月22日
    hdkさん (04/24 08:36)
    「うちのHHFZ4310は15年突破しまし...」
  • link 24年4月22日
    すずきさん (04/24 00:37)
    「ちゃんと数えてないですけど蛍光管が10年...」
  • link 24年4月22日
    hdkさん (04/23 20:52)
    「おお... うちのHHFZ4310より後...」
  • link 20年6月19日
    すずきさん (04/06 22:54)
    「ディレクトリを予め作成しておけば良いです...」
  • link 20年6月19日
    斎藤さん (04/06 16:25)
    「「Preferencesというメニューか...」

最近の記事3件

  • link 24年4月25日
    すずき (04/26 16:49)
    「[AVIFの変換] AVIFが読めないアプリケーションがたまにあるので、AVIF(AV1 Image File Format)...」
  • link 24年2月7日
    すずき (04/24 02:52)
    「[複数の音声ファイルのラウドネスを統一したい] PCやデジタル音楽プレーヤーで音楽を聞いていると、曲によって音量の大小が激しく...」
  • link 24年4月22日
    すずき (04/23 20:13)
    「[仕事部屋の照明が壊れた] いきなり仕事部屋のシーリングライトが消えました。蛍光管の寿命にしては去年(2022年10月19日の...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
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 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

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

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 04/26 16:49