コグノスケ


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

link もっと前
2021年4月5日 >>> 2021年3月23日
link もっと後

2021年4月5日

GCCを調べる - GCC 8.3のfoldingバグ - 解決編

目次: GCC

GCC 9.1との比較でpass_forwpropより早いタイミングでcargf() → atan2f() の置き換えをすれば良さそうであることがわかりました。

さらにGCC 9.1の動作を追うとpass_lower_cfでcargf() → atan2f() の置き換えをしている箇所が、下記の箇所であることがわかります。

pass_lower_cfでcargf() → atan2f() の置き換えを行う方法

// gcc/gcc/gimple-low.c

class pass_lower_cf : public gimple_opt_pass
{
public:
  pass_lower_cf (gcc::context *ctxt)
    : gimple_opt_pass (pass_data_lower_cf, ctxt)
  {}

  /* opt_pass methods: */
  virtual unsigned int execute (function *) { return lower_function_body (); }    //★★これ

}; // class pass_lower_cf


/* Lower the body of current_function_decl from High GIMPLE into Low
   GIMPLE.  */

static unsigned int
lower_function_body (void)
{
  struct lower_data data;
  gimple_seq body = gimple_body (current_function_decl);
  gimple_seq lowered_body;
  gimple_stmt_iterator i;
  gimple *bind;
  gimple *x;

...

  bind = gimple_seq_first_stmt (body);
  lowered_body = NULL;
  gimple_seq_add_stmt (&lowered_body, bind);
  i = gsi_start (lowered_body);
  lower_gimple_bind (&i, &data);    //★★これ

...


/* Lower a bind_expr TSI.  DATA is passed through the recursion.  */

static void
lower_gimple_bind (gimple_stmt_iterator *gsi, struct lower_data *data)
{
  tree old_block = data->block;
  gbind *stmt = as_a <gbind *> (gsi_stmt (*gsi));
  tree new_block = gimple_bind_block (stmt);

...

  lower_sequence (gimple_bind_body_ptr (stmt), data);    //★★これ

...


static void
lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
{
  gimple *stmt = gsi_stmt (*gsi);

  gimple_set_block (stmt, data->block);

  switch (gimple_code (stmt))
    {

...

    case GIMPLE_CALL:
      {
	tree decl = gimple_call_fndecl (stmt);
	unsigned i;

	for (i = 0; i < gimple_call_num_args (stmt); i++)
	  {
	    tree arg = gimple_call_arg (stmt, i);
	    if (EXPR_P (arg))
	      TREE_SET_BLOCK (arg, data->block);
	  }

	if (decl
	    && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
	  {
	    if (DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP)
	      {
		lower_builtin_setjmp (gsi);
		data->cannot_fallthru = false;
		return;
	      }
	    else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_POSIX_MEMALIGN
		     && flag_tree_bit_ccp
		     && gimple_builtin_call_types_compatible_p (stmt, decl))
	      {
		lower_builtin_posix_memalign (gsi);
		return;
	      }
	  }

	if (decl && (flags_from_decl_or_type (decl) & ECF_NORETURN))
	  {
	    data->cannot_fallthru = true;
	    gsi_next (gsi);
	    return;
	  }

	  //★★
	  //GCC 9.1だと下記のようなfold_stmt() を呼ぶ処理があるが、GCC 8.3には存在しない
	  //GCC 8.3に同様の処理を足すときは #include "gimple-fold.h" も足す必要がある

	  /* We delay folding of built calls from gimplification to
	     here so the IL is in consistent state for the diagnostic
	     machineries job.  */
	  if (gimple_call_builtin_p (stmt))
	    fold_stmt (gsi);
      }
      break;

...

この変更を加えるとinternal compile errorが出なくなります。

発生条件の理由

最初に、このエラーの発生条件の1つとしてTarget triplet(※)のoperatingsystem = elfになっていることを挙げました。

理由はoperationgsystem = linuxにするとimplicit_pが最初から全てセットされた状態でコンパイル処理が始まるからです。GCC 8.3でもpass_forwpropより早い段階でcargf() → atan2f() の置き換えが発生し、バグを隠してしまいます。

elfとlinuxのときのimplicit_pの違い

// gcc/gcc/builtins.def

/* Builtin that is specified by C99 and C90 reserve the name for future use.
   We can still recognize the builtin in C90 mode but we can't produce it
   implicitly.  */
#undef DEF_C99_C90RES_BUILTIN
#define DEF_C99_C90RES_BUILTIN(ENUM, NAME, TYPE, ATTRS)	\
  DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,	\
	       true, true, !flag_isoc99, ATTRS, targetm.libc_has_function (function_c99_misc), true)

...

/* Category: math builtins.  */
DEF_LIB_BUILTIN        (BUILT_IN_ACOS, "acos", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
DEF_C99_C90RES_BUILTIN (BUILT_IN_ACOSF, "acosf", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)

...

//★★atan2fはfn_class = function_c99_miscを渡してlibc_has_function() を呼ぶ★★


// gcc/gcc/config/linux.h

/* Determine what functions are present at the runtime;
   this includes full c99 runtime and sincos.  */
# undef TARGET_LIBC_HAS_FUNCTION
# define TARGET_LIBC_HAS_FUNCTION linux_libc_has_function


// gcc/gcc/config/linux.c

bool
linux_libc_has_function (enum function_class fn_class)
{
  if (OPTION_GLIBC || OPTION_MUSL)
    return true;
  if (OPTION_BIONIC)
    if (fn_class == function_c94
	|| fn_class == function_c99_misc
	|| fn_class == function_sincos)
	return true;    //★★operatingsystem = linuxのときはacosfのimplicit_pの初期値はtrue

  return false;
}


// gcc/gcc/config/elfos.h

#undef TARGET_LIBC_HAS_FUNCTION
#define TARGET_LIBC_HAS_FUNCTION no_c99_libc_has_function


// gcc/gcc/targhooks.c

bool
no_c99_libc_has_function (enum function_class fn_class ATTRIBUTE_UNUSED)
{
  return false;    //★★operatingsystem = elfのときはimplicit_pの初期値はfalse
}

最初は、この発生条件に気づかなくてGCC 8.3のバグだと気づくのがだいぶ遅れました……。

参考

関数cargf() やatan2f() はビルトイン関数のため、何も宣言しなくても関数の実体が存在します。しかし最適化を有効にするには、あえて関数宣言する必要があります。関数宣言しないとimplicit_pフラグがセットされない仕組みになっているからです。

analyze_functions(true) からimplicit_pの設定までの経路

// gcc/gcc/cgraphunit.c

void
symbol_table::finalize_compilation_unit (void)
{

...

  /* Gimplify and lower all functions, compute reachability and
     remove unreachable nodes.  */
  analyze_functions (/*first_time=*/true);    //★★これ

...


static void
analyze_functions (bool first_time)
{
  /* Keep track of already processed nodes when called multiple times for
     intermodule optimization.  */
  cgraph_node *first_handled = first_analyzed;
  varpool_node *first_handled_var = first_analyzed_var;
  hash_set<void *> reachable_call_targets;

  symtab_node *node;
  symtab_node *next;
  int i;
  ipa_ref *ref;
  bool changed = true;
  location_t saved_loc = input_location;

...

  /* Analysis adds static variables that in turn adds references to new functions.
     So we need to iterate the process until it stabilize.  */
  while (changed)
    {

...

      /* Lower representation, build callgraph edges and references for all trivially
         needed symbols and all symbols referred by them.  */
      while (queued_nodes != &symtab_terminator)
	{
	  changed = true;
	  node = queued_nodes;
	  queued_nodes = (symtab_node *)queued_nodes->aux;
	  cgraph_node *cnode = dyn_cast <cgraph_node *> (node);

...

	      if (!cnode->analyzed)
		cnode->analyze ();    //★★これ

...


/* Analyze the function scheduled to be output.  */
void
cgraph_node::analyze (void)
{
  if (native_rtl_p ())
    {
      analyzed = true;
      return;
    }

  tree decl = this->decl;
  location_t saved_loc = input_location;
  input_location = DECL_SOURCE_LOCATION (decl);

...


  if (alias)
    resolve_alias (cgraph_node::get (alias_target), transparent_alias);
  else if (dispatcher_function)
    {
...
    }
  else
    {
      push_cfun (DECL_STRUCT_FUNCTION (decl));

      assign_assembler_name_if_needed (decl);

      /* Make sure to gimplify bodies only once.  During analyzing a
	 function we lower it, which will require gimplified nested
	 functions, so we can end up here with an already gimplified
	 body.  */
      if (!gimple_has_body_p (decl))
	gimplify_function_tree (decl);    //★★これ

...


// gcc/gcc/gimplify.c

/* Entry point to the gimplification pass.  FNDECL is the FUNCTION_DECL
   node for the function we want to gimplify.

   Return the sequence of GIMPLE statements corresponding to the body
   of FNDECL.  */
void
gimplify_function_tree (tree fndecl)
{
  tree parm, ret;
  gimple_seq seq;
  gbind *bind;

...

  bind = gimplify_body (fndecl, true);    //★★これ

...


/* Gimplify the body of statements of FNDECL and return a GIMPLE_BIND node
   containing the sequence of corresponding GIMPLE statements.  If DO_PARMS
   is true, also gimplify the parameters.  */

gbind *
gimplify_body (tree fndecl, bool do_parms)
{
  location_t saved_location = input_location;
  gimple_seq parm_stmts, parm_cleanup = NULL, seq;
  gimple *outer_stmt;
  gbind *outer_bind;
  struct cgraph_node *cgn;

...

  /* Gimplify the function's body.  */
  seq = NULL;
  gimplify_stmt (&DECL_SAVED_TREE (fndecl), &seq);    //★★これ

...


/* Gimplify an expression which appears at statement context.  The
   corresponding GIMPLE statements are added to *SEQ_P.  If *SEQ_P is
   NULL, a new sequence is allocated.

   Return true if we actually added a statement to the queue.  */

bool
gimplify_stmt (tree *stmt_p, gimple_seq *seq_p)
{
  gimple_seq_node last;

  last = gimple_seq_last (*seq_p);
  gimplify_expr (stmt_p, seq_p, NULL, is_gimple_stmt, fb_none);    //★★これ
  return last != gimple_seq_last (*seq_p);
}


enum gimplify_status
gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
	       bool (*gimple_test_f) (tree), fallback_t fallback)
{

...

  /* Loop over the specific gimplifiers until the toplevel node
     remains the same.  */
  do
    {

...

      /* Make sure that all the cases set 'ret' appropriately.  */
      ret = GS_UNHANDLED;
      switch (TREE_CODE (*expr_p))
	{

...

	case BIND_EXPR:
	  ret = gimplify_bind_expr (expr_p, pre_p);    //★★これ
	  break;

...


//★★以降は
// gimplify_bind_expr
// gimplify_stmt
//
// gimplify_expr
// gimplify_statement_list
// gimplify_stmt
//
// gimplify_expr
// gimplify_call_expr
//
// gimplify_expr
// gimplify_addr_expr
//
// こんな感じ


/* Rewrite the ADDR_EXPR node pointed to by EXPR_P

      unary_expr
	      : ...
	      | '&' varname
	      ...

    PRE_P points to the list where side effects that must happen before
	*EXPR_P should be stored.

    POST_P points to the list where side effects that must happen after
	*EXPR_P should be stored.  */

static enum gimplify_status
gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
{
  tree expr = *expr_p;
  tree op0 = TREE_OPERAND (expr, 0);
  enum gimplify_status ret;
  location_t loc = EXPR_LOCATION (*expr_p);

  switch (TREE_CODE (op0))
    {

...

    default:
      /* If we see a call to a declared builtin or see its address
	 being taken (we can unify those cases here) then we can mark
	 the builtin for implicit generation by GCC.  */
      if (TREE_CODE (op0) == FUNCTION_DECL
	  && DECL_BUILT_IN_CLASS (op0) == BUILT_IN_NORMAL
	  && builtin_decl_declared_p (DECL_FUNCTION_CODE (op0)))
	set_builtin_decl_implicit_p (DECL_FUNCTION_CODE (op0), true);    //★★これ

...


//★★このif文が成立するにはcargfやatan2f関数を宣言する必要がある。
//
// TREE_CODE (op0) == FUNCTION_DECL
// DECL_BUILT_IN_CLASS (op0) == BUILT_IN_NORMAL
// builtin_decl_declared_p (DECL_FUNCTION_CODE (op0)): cargfやatan2fを関数宣言しないとtrueにならない
//
// ソースコードから、下記の宣言を削除すると、
//
// float cargf(float _Complex z);
// float atan2f(float y, float x);
//
// TREE_CODE (op0) == FUNCTION_DECL                 : 1
// DECL_BUILT_IN_CLASS (op0) == BUILT_IN_NORMAL     : 1
// builtin_decl_declared_p (DECL_FUNCTION_CODE (op0): 0


// gcc/gcc/tree.h

/* Set the implicit flag for a builtin function.  */

static inline void
set_builtin_decl_implicit_p (enum built_in_function fncode, bool implicit_p)
{
  size_t uns_fncode = (size_t)fncode;

  gcc_checking_assert (BUILTIN_VALID_P (fncode)
		       && builtin_info[uns_fncode].decl != NULL_TREE);

  builtin_info[uns_fncode].implicit_p = implicit_p;    //★★implicit_pが書き換わる
}

ソースコードからcargf() やatan2f() の宣言を削除すると、implicit_pがセットされなくなってcargf() をatan2f() に置き換える最適化が発動しなくなります。cargf() が存在しないような環境(C89など)のためですかね……?

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

コメント一覧

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



2021年4月4日

GCCを調べる - GCC 8.3のfoldingバグ - GCC 9.1との比較

目次: GCC

実はGCC 9.1ではcarg, atan2を並べてもエラーが発生しませんので、バグがどこかで直っています。GCC 9.1と8.3の動作の違いを調べることで、原因と直し方がわかるはずです。

cargの変換

GIMPLEを出力しながらコードを追っていくと、下記の関数でcargがatan2に変換され、その後internal compile errorになるようです。

cargの変換箇所

// gcc/gcc/builtins.c

/* Fold a call to builtin carg(a+bi) -> atan2(b,a).  */

static tree
fold_builtin_carg (location_t loc, tree arg, tree type)
{
  if (validate_arg (arg, COMPLEX_TYPE)
      && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE)
    {
      tree atan2_fn = mathfn_built_in (type, BUILT_IN_ATAN2);    //★★この関数がNULL以外を返す条件がある

      if (atan2_fn)
        {
  	  tree new_arg = builtin_save_expr (arg);    //★★ここにくるとcarg → atan2に変換される
	  tree r_arg = fold_build1_loc (loc, REALPART_EXPR, type, new_arg);
	  tree i_arg = fold_build1_loc (loc, IMAGPART_EXPR, type, new_arg);
	  return build_call_expr_loc (loc, atan2_fn, 2, i_arg, r_arg);
	}
    }

  return NULL_TREE;
}

関数mathfn_built_in() はbuiltin_info[uns_fncode].implicit_pがセットされていないとNULLを返す仕組みになっています。

mathfn_built_in() の実装

// gcc/gcc/builtins.c

/* Like mathfn_built_in_1, but always use the implicit array.  */

tree
mathfn_built_in (tree type, combined_fn fn)
{
  return mathfn_built_in_1 (type, fn, /*implicit=*/ 1);    //★★
}

/* Return mathematic function equivalent to FN but operating directly on TYPE,
   if available.  If IMPLICIT_P is true use the implicit builtin declaration,
   otherwise use the explicit declaration.  If we can't do the conversion,
   return null.  */

static tree
mathfn_built_in_1 (tree type, combined_fn fn, bool implicit_p)
{
  built_in_function fcode2 = mathfn_built_in_2 (type, fn);
  if (fcode2 == END_BUILTINS)
    return NULL_TREE;

  if (implicit_p && !builtin_decl_implicit_p (fcode2))    //★★implicit_pフラグがセットされないと変換されない
    return NULL_TREE;

  return builtin_decl_explicit (fcode2);    //★★指定された数学関数のtreeを返す(今回はatan2f)
}


// gcc/gcc/tree.h

/* Return whether the standard builtin function can be used implicitly.  */

static inline bool
builtin_decl_implicit_p (enum built_in_function fncode)
{
  size_t uns_fncode = (size_t)fncode;

  gcc_checking_assert (BUILTIN_VALID_P (fncode));
  return (builtin_info[uns_fncode].decl != NULL_TREE
	  && builtin_info[uns_fncode].implicit_p);    //★★implicit_pフラグがセットされないと変換されない
}


// gcc/gcc/builtins.c

#define CASE_MATHFN(MATHFN) \
  CASE_CFN_##MATHFN: \
  fcode = BUILT_IN_##MATHFN; fcodef = BUILT_IN_##MATHFN##F ; \
  fcodel = BUILT_IN_##MATHFN##L ; break;


/* Return a function equivalent to FN but operating on floating-point
   values of type TYPE, or END_BUILTINS if no such function exists.
   This is purely an operation on function codes; it does not guarantee
   that the target actually has an implementation of the function.  */

static built_in_function
mathfn_built_in_2 (tree type, combined_fn fn)
{
  tree mtype;

...

  switch (fn)
    {
...
    CASE_MATHFN (ATAN)
    CASE_MATHFN (ATAN2)    //★★ここにヒットしてbreak
    CASE_MATHFN (ATANH)
    CASE_MATHFN (CBRT)
... 

    default:
      return END_BUILTINS;
    }

  mtype = TYPE_MAIN_VARIANT (type);
  if (mtype == double_type_node)
    return fcode;
  else if (mtype == float_type_node)
    return fcodef;    //★★ここにくる、返り値はBUILTIN_ATAN2F
  else if (mtype == long_double_type_node)
    return fcodel;
...
  else if (mtype == float128x_type_node)
    return fcodef128x;
  else
    return END_BUILTINS;
}

しかし、cargf → atan2f変換自体はおかしいことではないはずです。

GCC 9.1との比較

GCC 9.1と動作を比較してみます。

GCC 9.1 (OK)GCC 8.3 (NG)
analyze_functions(true) でimplicit_p: false → true analyze_functions(true) でimplicit_p: false → true
pass_lower_cfでcargf → atan2fに置き換え pass_forwpropでcargf → atan2fに置き換え
pass_lower_cfでimplicit_p: true → true pass_forwpropでimplicit_p: true → true
pass_build_ssaでvuseがSSA_NAMEに置き換わる (VAR_DECLのまま)
pass_forwpropでsimplify_builtin_call() pass_forwpropでsimplify_builtin_call() → エラー!!
implicit_p
cargf() をatan2f() に変換するfold_builtin_carg() が発動するかしないかを決めるフラグです。具体的にはbuiltin_info[16].implicit_pです。16はBUILT_IN_ATAN2Fの値です。
simplify_builtin_call()
最初に調べたとおりgimpleのvuseのチェックを行う箇所で、SSA_NAME以外だとinternal compile errorになります。

パスの実行順序は早い順にpass_lower_cf (008t.lower), pass_build_ssa (019t.ssa), pass_forwprop (029t.forwprop1) になります。カッコ内はGCC 9.1でdump-tree-allを指定したときのダンプファイルとの対応です。8.3の場合はpass_forwprop (033t.forwprop) になります。

動作の違いはcargf() → atan2f() の変換が行われるパスです。GCC 9.1はpass_lower_cfですが、GCC 8.3はpass_forwpropです。GCC 9.1は序盤のパスでcargf() → atan2f() の変換が行われるため、pass_build_ssaでvuseが適切に書き換えられて救われるようです。

光明が見えてきました。

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

コメント一覧

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



2021年4月3日

GCCを調べる - GCC 8.3のfoldingバグ - エラーの原因をvuseから追う

目次: GCC

最初に書いておくと、vuseから追う解析は正解には至りませんでしたが、試行錯誤のあとも一応残しておきます。再現環境とデバッグの準備ができました。エラーが発生する箇所を調べます。

エラー発生箇所

// gcc/gcc/tree-ssa-forwprop.c

static bool
simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
{
  gimple *stmt1, *stmt2 = gsi_stmt (*gsi_p);
  tree vuse = gimple_vuse (stmt2);
  if (vuse == NULL)
    return false;
  stmt1 = SSA_NAME_DEF_STMT (vuse);    //★★ここでエラー


// gcc/gcc/tree.h

/* Returns the statement which defines this SSA name.  */
#define SSA_NAME_DEF_STMT(NODE)	SSA_NAME_CHECK (NODE)->ssa_name.def_stmt


// gcc/gcc/tree-check.h

#define SSA_NAME_CHECK(t)	TREE_CHECK (t, SSA_NAME)


// gcc/gcc/tree.h

/* When checking is enabled, errors will be generated if a tree node
   is accessed incorrectly. The macros die with a fatal error.  */
#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)

//★★enable-checking=yesだとこちらが有効になるので、エラーが発生する

#define TREE_CHECK(T, CODE) \
(tree_check ((T), __FILE__, __LINE__, __FUNCTION__, (CODE)))

...

#else /* not ENABLE_TREE_CHECKING, or not gcc */

...

//★★enable-checking=releaseだとこちらが有効になるので、エラーが発生しない

#define TREE_CHECK(T, CODE)			(T)


// gcc/gcc/tree.h

//★★
// SSA_NAME_DEF_STMT (vuse)
// TREE_CHECK (vuse, SSA_NAME)
// tree_check (vuse, __FILE__, __LINE__, __FUNCTION__, SSA_NAME)
//
// vuseのTREE_CODEはVAR_DECL

inline tree
tree_check (tree __t, const char *__f, int __l, const char *__g, tree_code __c)
{
  if (TREE_CODE (__t) != __c)  //★★TREE_CODEがSSA_NAMEではないので、このチェックに引っかかる
    tree_check_failed (__t, __f, __l, __g, __c, 0);
  return __t;
}

正直、これを見ても「だから何??」ですよね。

vuseとは?

GCC Internalsを見てもいまいち要領を得ませんが、変数への参照を表しているようです。エラーの原因となっているので、調べるしかありません。どこから来るのでしょうか?

エラー発生箇所

// gcc/gcc/tree-ssa-forwprop.c

static bool
simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
{
  //★★stmt2はイテレータgsi_pが指している先頭の要素
  gimple *stmt1, *stmt2 = gsi_stmt (*gsi_p);

  //★★vuseはgimple stmt2をgimple_statement_with_memory_opsにキャストしたときのvuseメンバ
  tree vuse = gimple_vuse (stmt2);

  if (vuse == NULL)
    return false;
  stmt1 = SSA_NAME_DEF_STMT (vuse);    //★★ここでエラー


// gcc/gcc/gimple.h

/* Return the single VUSE operand of the statement G.  */

static inline tree
gimple_vuse (const gimple *g)
{
  const gimple_statement_with_memory_ops *mem_ops_stmt =
     dyn_cast <const gimple_statement_with_memory_ops *> (g);
  if (!mem_ops_stmt)
    return NULL_TREE;
  return mem_ops_stmt->vuse;
}


// gcc/gcc/gimple-iterator.h

/* Return the current stmt.  */

static inline gimple *
gsi_stmt (gimple_stmt_iterator i)
{
  return i.ptr;
}

このvuseメンバを設定するのはどこでしょうか?ソースコードから探すのは困難そうなので、watchpointで探しましょう。

vuseの値とアドレスを調べる
$ gdb /path/to/build/_install/libexec/gcc/x86_64-unknown-elf/8.3.0/cc1

(gdb) r -quiet a.c -mtune=generic -march=x86-64 -g -O2 -Wall -std=c99 -o zzzzzzzz.s

...エラーが出ることを確認する...

(gdb) b tree-ssa-forwprop.c:1246

Breakpoint 1 at 0x11360b5: file ../../gcc/tree-ssa-forwprop.c, line 1246.

(gdb) r

Breakpoint 1, simplify_builtin_call (gsi_p=0x7fffffffd680,
    callee2=0x7ffff74af300) at ../../gcc/tree-ssa-forwprop.c:1246
1246      stmt1 = SSA_NAME_DEF_STMT (vuse);

(gdb) p *stmt2

$2 = {code = GIMPLE_CALL, no_warning = 0, visited = 0, nontemporal_move = 0,
...


★★code = GIMPLE_CALLなのでgcallにキャストしてもう一回ダンプ

(gdb) p *(gcall *)stmt2

$3 = {<gimple_statement_with_memory_ops_base> = {<gimple_statement_with_ops_base> = {<gimple> = {code = GIMPLE_CALL, no_warning = 0, visited = 0,
        nontemporal_move = 0, plf = 0, modified = 0, has_volatile_ops = 0,
        pad = 0, subcode = 0, uid = 0, location = 2147483655, num_ops = 5,
        bb = 0x7ffff7475410, next = 0x7ffff7476118, prev = 0x7ffff7599b90},
      use_ops = 0x7ffff75b14f8}, vdef = 0x7ffff7ffbf30,
    vuse = 0x7ffff7ffbf30}, ★★これ★★
    call_used = {anything = 1, nonlocal = 0,
...


★★stmt2->vuseのアドレスを調べる

(gdb) p &((gcall *)stmt2)->vuse

$4 = (tree *) 0x7ffff75b30c8

エラーが発生するときのvuseは0x7ffff7ffbf30で、vuseを持っている変数 ((gcall *)stmt2)->vuseのアドレスは0x7ffff75b30c8です。デバッグ時、アドレスは毎回同じになることを利用して、先程調べたアドレスにwatchpointを設定し、何か値が書き込まれたら止めます。

stmt2->vuseの書き換え箇所で止める
★★stmt2->vuseを書き換える箇所を特定するためwatchpointを設定する

(gdb) watch *(int *)0x7ffff75b30c8

(gdb) r

...memset系で止まるところは無視...

Old value = 0
New value = -134234320
gimple_set_vuse (g=0x7ffff75b3090, vuse=0x7ffff7ffbf30)
    at ../../gcc/gimple.h:2084
2084    }

それらしき関数gimple_set_vuse() が見つかりました。vuseの値も0x7ffff7ffbf30で関数simplify_builtin_call() で観測した値と一致しており、別の用事で書き換えられたわけではなさそうです。

さらに追っていくと、vuseはcfun->gimple_df->vopが元になっていることがわかり、cfun->gimple_df->vopはcreate_vop_var() によって生成されていることがわかるのですが、そこで行き詰まってしまいます。GCCはエラーメッセージからエラーが発生した箇所はすぐにわかります。しかしエラーの原因はわからないことがほとんどです。GCCのデバッグの辛いところですね。

別のアプローチが必要そうです。

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

コメント一覧

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



2021年4月2日

GCCを調べる - GCC 8.3のfoldingバグ - 発生条件

目次: GCC

GCC 8.3のバグを追った記録です。来月になったら絶対に忘れて、説明できなくなるので、できる限り詳細にメモしておきたいと思います。

再現条件: コード

再現は簡単で、下記のコードをコンパイルするとinternal compile errorになります。

エラーになるコード

float cargf(float _Complex z);
float atan2f(float y, float x);

void func(float _Complex cval, float val)
{
	__builtin_cargf(cval);
	__builtin_atan2f(val, 1.0f);
}
エラーメッセージ
$ x86_64-unknown-elf-gcc -Wall -O2 -g a.c

a.c: In function 'func':
a.c:7:2: warning: statement with no effect [-Wunused-value]
  __builtin_cargf(cval);
  ^~~~~~~~~~~~~~~~~~~~~
during GIMPLE pass: forwprop
a.c:9:1: internal compiler error: tree check: expected ssa_name, have var_decl in simplify_builtin_call, at tree-ssa-forwprop.c:1246
 }
 ^
0x1331604 tree_check_failed(tree_node const*, char const*, int, char const*, ...)
        ../../gcc/tree.c:9338
0x7ca7f2 tree_check(tree_node*, char const*, int, char const*, tree_code)
        ../../gcc/tree.h:3142
0x1135fb9 simplify_builtin_call
        ../../gcc/tree-ssa-forwprop.c:1246
0x113b55f execute
        ../../gcc/tree-ssa-forwprop.c:2527
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

再現にあたり重要なポイントは2点です。

  • carg, atan2を関数宣言する
  • carg, atan2の順に呼ぶ(単独、逆だとエラーにならない)

なぜこの2点が重要か?については、追々説明します。この条件だけで原因が「ああ、あれか」と見当がつく人は超凄いです。GCCマスターか天才ですね。この記事は一切読む必要がないです。ちなみに私は解析に1週間近く掛かりました。辛かったです……。

再現条件: コンパイラ

このエラーはディストリビューションが配布するGCC 8.3のバイナリでは発生しません。x86_64向けのGCCでも発生させるには、下記に示すように特殊なビルド条件にする必要があります。

  • Target triplet(※)のoperatingsystem = elfになっていること(ディストリビューションが配布するバイナリはlinux-gnuなので該当しない)
  • enable-checking=yesでビルドする(ディストリビューションが配布するバイナリはenable-checking=releaseのことが多いので該当しない)

(※)GNUのビルドシステムが使うシステム名の表し方です。machine-vendor-operatingsystemの順で表します。

PC向けでは特殊なビルド条件ですが、ベアメタル向けのクロスコンパイラだと、割とこの条件に当てはまるものは多いです。

ビルドコンフィグ例
$ ../configure \
  --target=x86_64-unknown-elf \
  --prefix=/path/to/gcc/build/_install \
  --disable-bootstrap \
  --disable-libsanitizer \
  --enable-checking=yes \
  --enable-languages="c,c++" \
  CFLAGS="-g -O0 -fno-inline" \
  CXXFLAGS="-g -O0 -fno-inline"

$ make -j8 all-gcc
$ make install-gcc

ビルドコンフィグの一例を示しました。disable-bootstrapはデバッグ用ビルドオプション(CFLAGS, CXXFLAGS)を指定するために使っています(詳しくは 2021年3月30日の日記参照)。disable-libsanitizerは私の環境でビルドエラーになったので、仕方なくビルド対象から外しています。enable-languagesはFortranなどの今回使わない言語を削ってビルド時間を短縮するためです。

デバッグ

デバッグする対象はおなじみcc1です。なぜcc1なのかは以前書いた(2019年5月17日の日記参照)とおりです。

デバッグの例
#### gdbでデバッグするなら

$ gdb /path/to/build/_install/libexec/gcc/x86_64-unknown-elf/8.3.0/cc1

(gdb) run -quiet a.c -mtune=generic -march=x86-64 \
  -g -O2 -Wall -std=c99 -o zzzzzzzz.s


#### gdbserverを使うなら

$ gdbserver --multi localhost:1234 \
  -quiet a.c -mtune=generic -march=x86-64 \
  -g -O2 -Wall -std=c99 -o zzzzzzzz.s

問題の再現と、GCCのコードを追う準備ができました。

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

コメント一覧

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



2021年3月30日

GCCを調べる - デバッグ環境再び(ブートストラップモード)

目次: GCC

前回(2021年3月29日の日記参照)はconfigureオプションに --disable-bootstrapを指定してブートストラップモードを無効にしてビルドしました。ブートストラップモードが有効なときについても、メモしておこうと思います。

ブートストラップモードはホストのコンパイラでSTAGE1コンパイラをビルドし、STAGE1コンパイラを使ってSTAGE2とSTAGE3コンパイラをビルドして、ビルド結果に食い違いがないことを比較するモードです。ライブラリのビルドなどに使われる(最終的にインストールされる)のはSTAGE3のコンパイラのようです。3回GCCをビルドするので、ビルド時間は非ブートストラップモードの3倍近い時間がかかります。

ビルドオプションの変え方

ブートストラップモードのときはconfigureにCFLAGS, CXXFLAGSを指定する方法は使えません。代わりに GCCのマニュアルに記載がある通りmake BOOT_CFLAGS="-O0 -g -fno-inline" bootstrapとすれば良いです。

こちらがおそらく正規の手順で、configureにCFLAGS, CXXFLAGSを指定する方法は邪道なんでしょうけど、ブートストラップモードはビルドが遅くて辛いんだよなー……。

最適化をOFFにしてブートストラップモードでGCCをビルド
$ mkdir build
$ cd build

$ ../configure \
  --prefix=`pwd`/_install \
  --enable-languages=c,c++

$ make -j8 BOOT_CFLAGS="-O0 -g -fno-inline" bootstrap
$ make install

ただしBOOT_CFLAGSの指定はSTAGE1には効きません。STAGE1だけは常に手堅い安定したオプションでビルドされます。

STAGE1のCFLAGSは固定

# gcc/Makefile.in

...

# Flags to pass to stage2 and later makes.  They are defined
# here so that they can be overridden by Makefile fragments.
BOOT_CFLAGS= -g -O2
BOOT_LDFLAGS=
BOOT_ADAFLAGS= -gnatpg

...

# Defaults for all stages; some are overridden below.

STAGE_CFLAGS = $(BOOT_CFLAGS)    ★★STAGE_CFLAGS = BOOT_CFLAGS★★
STAGE_TFLAGS = $(TFLAGS)
STAGE_CONFIGURE_FLAGS=@stage2_werror_flag@

# Defaults for stage 1; some are overridden below.
STAGE1_CFLAGS = $(STAGE_CFLAGS)    ★★STAGE1_CFLAGS = STAGE_CFLAGS★★
STAGE1_CXXFLAGS = $(CXXFLAGS)
@if target-libstdc++-v3-bootstrap
# Override the above if we're bootstrapping C++.
STAGE1_CXXFLAGS = $(STAGE1_CFLAGS)
@endif target-libstdc++-v3-bootstrap

...

# By default, C and C++ are the only stage1 languages, because they are the
# only ones we require to build with the bootstrap compiler, and also the
# only ones useful for building stage2.

STAGE1_CFLAGS = @stage1_cflags@    ★★STAGE1_CFLAGSだけ無理やり上書きされる★★
STAGE1_CHECKING = @stage1_checking@
STAGE1_LANGUAGES = @stage1_languages@

当然ですがSTAGE2とSTAGE3には設定が反映されます。STAGE1コンパイラを手動で使って何かビルドする人はほぼいないと思うので、特に問題ないでしょう。

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

コメント一覧

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



2021年3月29日

GCCを調べる - デバッグ環境再び

目次: GCC

去年あたりにGCCのデバッグ環境について書きました(2019年5月17日の日記参照)。GDBでGCCの動作を調べる際に、最適化が効いていると色々デバッグ時に不都合が生じます。例えば、

  • ブレークポイントが設定できない箇所が生じる(インライン関数、最適化で消える部分など)
  • 関数コールのバックトレースが不完全、動作と合わない(インライン関数、末尾最適化でretが消える場合など)
  • 引数、ローカル変数の値がoptimized outされて読めない

通常のアプリケーションだと気になりませんが、相手は魔界GCCです。勝手にブレークポイントがずれてもらってはたまったものではないです。こういうときはGCCのビルドオプションを変えて、最適化を全てOFFにしてしまうと見やすいです。

環境はDebian Testingです。GCCは8.3を使っています。

最適化をOFFにしてGCCをビルド
$ mkdir build
$ cd build

$ ../configure \
  --prefix=`pwd`/_install \
  --enable-languages=c,c++ \
  --disable-libsanitizer \
  --disable-bootstrap \
  CFLAGS="-O0 -g -fno-inline" \
  CXXFLAGS="-O0 -g -fno-inline"

$ make -j8
$ make install

私はCとC++ だけ使えれば良いので、--enable-languages=c,c++ を指定して、ついでにビルド時間短縮しています。C以外の言語(Fortranなど)に用事がある場合は、適宜足してください。Debian TestingでGCC 8.3をビルドするとなんでかlibsanitizerがビルドエラーになった(深追いしてません)ので、--disable-libsanitizerを付けて回避しました。環境によっては要らないかも?

また、ブートストラップモードだと、ビルドに時間がかかりすぎるので --disable-bootstrapで無効にしています。ビルドオプションは "-O0 -g -fno-inline" 最適化なし、デバッグ情報あり、インライン展開なし、です。

インストール先はどこでも良いですが、インストールするディレクトリは、build下の _installディレクトリにしています。buildディレクトリと一緒に消せて、間違って古いバイナリを使う心配がほぼないため、最近お気に入りのインストール先です。

最適化ありの場合

オプション -O2 -gでビルドしたバイナリを使って、GDBでインライン関数にブレークポイントを設定すると、こんなふうになります。

ブレークポイント設定先の関数

/* Set the implicit flag for a builtin function.  */

static inline void
set_builtin_decl_implicit_p (enum built_in_function fncode, bool implicit_p)
{
  size_t uns_fncode = (size_t)fncode;

  gcc_checking_assert (BUILTIN_VALID_P (fncode)
		       && builtin_info[uns_fncode].decl != NULL_TREE);

  builtin_info[uns_fncode].implicit_p = implicit_p;    //★ここにブレークポイントを設定★
}
static inline関数でブレークポイント(最適化あり)
$ gdb /path/to/gcc/build/_install/libexec/gcc/x86_64-pc-linux-gnu/8.3.0/cc1

(gdb) b tree.h:5245
Breakpoint 1 at 0x7cc7c3: tree.h:5245. (2 locations)

(gdb) r -quiet -imultiarch x86_64-linux-gnu a.c -dumpbase a.c -mtune=generic \
  -march=x86-64 -auxbase a -g -O2 -Wall -std=c99 -o zzzzzzzz.s

Breakpoint 1, set_builtin_decl_implicit_p (implicit_p=true, fncode=12304)
    at ../../gcc/tree.h:5245
5245      builtin_info[uns_fncode].implicit_p = implicit_p;

(gdb) p uns_fncode

$1 = <optimized out>

一応ブレークはしますが、表示がおかしいです。引数の順序が逆ですし、fncodeの値もおかしい(16のはず)です。ローカル変数は最適化によって消されてprint不可能です。

バックトレース(最適化あり)
#0  set_builtin_decl_implicit_p (implicit_p=true, fncode=12304)
    at ../../gcc/tree.h:5245
#1  gimplify_addr_expr (expr_p=expr_p@entry=0x7ffff76682e0, pre_p=pre_p@entry=0x7fffffffd600, post_p=post_p@entry=0x7fffffffd190)
    at ../../gcc/gimplify.c:6051
#2  0x000000000084301d in gimplify_expr (expr_p=0x7ffff76682e0, pre_p=<optimized out>, post_p=<optimized out>, gimple_test_f=<optimized out>, fallback=<optimized out>)
    at ../../gcc/gimplify.c:11581
#3  0x0000000000846a55 in gimplify_call_expr (expr_p=0x7ffff77eaee0, pre_p=0x7fffffffd600, want_value=<optimized out>)
    at ../../gcc/gimplify.c:3308
#4  0x00000000008436d6 in gimplify_expr (expr_p=0x7ffff77eaee0, pre_p=<optimized out>, post_p=<optimized out>, gimple_test_f=<optimized out>, fallback=<optimized out>)
    at ../../gcc/gimplify.c:11506
#5  0x0000000000843c0e in gimplify_stmt (seq_p=<optimized out>, stmt_p=<optimized out>)
    at ../../gcc/gimplify.c:6690
#6  gimplify_statement_list (pre_p=<optimized out>, expr_p=0x7ffff743ddd0)
    at ../../gcc/gimplify.c:1764
#7  gimplify_expr (expr_p=0x7ffff743ddd0, pre_p=<optimized out>, post_p=<optimized out>, gimple_test_f=<optimized out>, fallback=<optimized out>)
    at ../../gcc/gimplify.c:11963
#8  0x0000000000848f42 in gimplify_stmt (seq_p=0x7fffffffd600, stmt_p=0x7ffff743ddd0)
    at ../../gcc/gimplify.c:6690
#9  gimplify_bind_expr (expr_p=expr_p@entry=0x7ffff744b1c0, pre_p=pre_p@entry=0x7fffffffd7e8)
    at ../../gcc/gimplify.c:1331
#10 0x000000000084344b in gimplify_expr (expr_p=0x7ffff744b1c0, pre_p=<optimized out>, post_p=<optimized out>, gimple_test_f=<optimized out>, fallback=<optimized out>)
    at ../../gcc/gimplify.c:11735
#11 0x0000000000847508 in gimplify_stmt (seq_p=0x7fffffffd7e8, stmt_p=0x7ffff744b1c0)
    at ../../gcc/gimplify.c:6690
#12 gimplify_body (fndecl=0x7ffff744b100, do_parms=<optimized out>)
    at ../../gcc/gimplify.c:12735
#13 0x00000000008478e6 in gimplify_function_tree (fndecl=fndecl@entry=0x7ffff744b100)
    at ../../gcc/gimplify.c:12900
#14 0x00000000006f6ab0 in cgraph_node::analyze (this=0x7ffff74472e0)
    at ../../gcc/cgraphunit.c:670
#15 0x00000000006f8e68 in analyze_functions (first_time=<optimized out>)
    at ../../gcc/cgraphunit.c:1131
#16 0x00000000006f99c3 in symbol_table::finalize_compilation_unit (this=0x7ffff7658100)
    at ../../gcc/cgraphunit.c:2691
#17 0x0000000000a689fb in compile_file ()
    at ../../gcc/toplev.c:480
#18 0x00000000005bbe3d in do_compile ()
    at ../../gcc/toplev.c:2132
#19 toplev::main (this=this@entry=0x7fffffffda9e, argc=<optimized out>, argc@entry=17, argv=<optimized out>, argv@entry=0x7fffffffdba8)
    at ../../gcc/toplev.c:2267
#20 0x00000000005be0cf in main (argc=17, argv=0x7fffffffdba8)
    at ../../gcc/main.c:39

このケースだとバックトレースに抜けはなさそうですが、表示される引数にoptimized outが多く、何が渡されたのかわかりません。

最適化なしの場合

ビルドオプション -O0 -g -fno-inlineでビルドして、GDBでインライン関数にブレークを設定します。

static inline関数にブレークポイント(最適化なし)
$ gdb /path/to/gcc/build/_install/libexec/gcc/x86_64-pc-linux-gnu/8.3.0/cc1

(gdb) b tree.h:5245
Breakpoint 1 at 0x7cc7c3: tree.h:5245. (2 locations)

(gdb) r -quiet -imultiarch x86_64-linux-gnu a.c -dumpbase a.c -mtune=generic \
  -march=x86-64 -auxbase a -g -O2 -Wall -std=c99 -o zzzzzzzz.s

Breakpoint 1, set_builtin_decl_implicit_p (fncode=BUILT_IN_ATAN2F,
    implicit_p=true) at ../../gcc/tree.h:5245
5245      builtin_info[uns_fncode].implicit_p = implicit_p;

(gdb) p uns_fncode

$1 = 16

引数のenumも名前で出ていますし、ローカル変数も表示できます。

バックトレース(最適化なし)
#0  set_builtin_decl_implicit_p (fncode=BUILT_IN_ATAN2F, implicit_p=true)
    at ../../gcc/tree.h:5245
#1  0x0000000000b55843 in gimplify_addr_expr (expr_p=0x7ffff76682e0, pre_p=0x7fffffffd3f0, post_p=0x7fffffffcc08)
    at ../../gcc/gimplify.c:6051
#2  0x0000000000b636a5 in gimplify_expr (expr_p=0x7ffff76682e0, pre_p=0x7fffffffd3f0, post_p=0x7fffffffcc08, gimple_test_f=0xb16def <is_gimple_call_addr(tree_node*)>, fallback=1)
    at ../../gcc/gimplify.c:11581
#3  0x0000000000b4f52c in gimplify_call_expr (expr_p=0x7ffff77eaee0, pre_p=0x7fffffffd3f0, want_value=false)
    at ../../gcc/gimplify.c:3308
#4  0x0000000000b6336e in gimplify_expr (expr_p=0x7ffff77eaee0, pre_p=0x7fffffffd3f0, post_p=0x7fffffffcf58, gimple_test_f=0xb5411f <is_gimple_stmt(tree)>, fallback=0)
    at ../../gcc/gimplify.c:11506
#5  0x0000000000b571dd in gimplify_stmt (stmt_p=0x7ffff77eaee0, seq_p=0x7fffffffd3f0)
    at ../../gcc/gimplify.c:6690
#6  0x0000000000b4bcb9 in gimplify_statement_list (expr_p=0x7ffff743ddd0, pre_p=0x7fffffffd3f0)
    at ../../gcc/gimplify.c:1764
#7  0x0000000000b647a5 in gimplify_expr (expr_p=0x7ffff743ddd0, pre_p=0x7fffffffd3f0, post_p=0x7fffffffd208, gimple_test_f=0xb5411f <is_gimple_stmt(tree)>, fallback=0)
    at ../../gcc/gimplify.c:11963
#8  0x0000000000b571dd in gimplify_stmt (stmt_p=0x7ffff743ddd0, seq_p=0x7fffffffd3f0)
    at ../../gcc/gimplify.c:6690
#9  0x0000000000b4ad3a in gimplify_bind_expr (expr_p=0x7ffff744b1c0, pre_p=0x7fffffffd708)
    at ../../gcc/gimplify.c:1331
#10 0x0000000000b63d56 in gimplify_expr (expr_p=0x7ffff744b1c0, pre_p=0x7fffffffd708, post_p=0x7fffffffd558, gimple_test_f=0xb5411f <is_gimple_stmt(tree)>, fallback=0)
    at ../../gcc/gimplify.c:11735
#11 0x0000000000b571dd in gimplify_stmt (stmt_p=0x7ffff744b1c0, seq_p=0x7fffffffd708)
    at ../../gcc/gimplify.c:6690
#12 0x0000000000b6610a in gimplify_body (fndecl=0x7ffff744b100, do_parms=true)
    at ../../gcc/gimplify.c:12735
#13 0x0000000000b66740 in gimplify_function_tree (fndecl=0x7ffff744b100)
    at ../../gcc/gimplify.c:12900
#14 0x00000000009798ad in cgraph_node::analyze (this=0x7ffff74472e0)
    at ../../gcc/cgraphunit.c:670
#15 0x000000000097aa60 in analyze_functions (first_time=true)
    at ../../gcc/cgraphunit.c:1131
#16 0x000000000097e71a in symbol_table::finalize_compilation_unit (this=0x7ffff7658100)
    at ../../gcc/cgraphunit.c:2691
#17 0x0000000000e79db0 in compile_file ()
    at ../../gcc/toplev.c:480
#18 0x0000000000e7c68a in do_compile ()
    at ../../gcc/toplev.c:2132
#19 0x0000000000e7c966 in toplev::main (this=0x7fffffffda7e, argc=18, argv=0x7fffffffdb88)
    at ../../gcc/toplev.c:2267
#20 0x00000000019e07e6 in main (argc=18, argv=0x7fffffffdb88)
    at ../../gcc/main.c:39

バックトレースの引数表示もうまくいっているようです。

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

コメント一覧

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



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 この記事にコメントする



link もっと前
2021年4月5日 >>> 2021年3月23日
link もっと後

管理用メニュー

link 記事を新規作成

<2021>
<<<04>>>
----123
45678910
11121314151617
18192021222324
252627282930-

最近のコメント5件

  • link 24年10月1日
    すずきさん (10/06 03:41)
    「xrdpで十分動作しているので、Wayl...」
  • link 24年10月1日
    hdkさん (10/03 19:05)
    「GNOMEをお使いでしたら今はWayla...」
  • link 24年10月1日
    すずきさん (10/03 10:12)
    「私は逆にVNCサーバーに繋ぐ使い方をした...」
  • link 24年10月1日
    hdkさん (10/03 08:30)
    「おー、面白いですね。xrdpはすでに立ち...」
  • link 14年6月13日
    2048player...さん (09/26 01:04)
    「最後に、この式を出すのに紙4枚(A4)も...」

最近の記事20件

  • link 24年10月31日
    すずき (11/04 15:17)
    「[DENSOの最終勤務日] 最終勤務日でした、入門カードや会社のPCを返却してきました。在籍期間はNSITEXE(品川のオフィ...」
  • link 22年7月8日
    すずき (11/02 20:34)
    「[マンガ紹介 - まとめリンク] 目次: マンガ紹介一覧が欲しくなったので作りました。5作品乙女ゲームの破滅フラグしかない悪役...」
  • link 24年10月30日
    すずき (11/02 20:33)
    「[マンガ紹介] 目次: マンガ紹介お気に入りのマンガ紹介シリーズ。最近完結した短めの作品を紹介します。マイナススキル持ち四人が...」
  • link 19年3月28日
    すずき (11/02 13:27)
    「[マンガ紹介] 目次: マンガ紹介お気に入りのマンガ紹介シリーズ。こわもてかわもて(全2巻、2019年)(アマゾンへのリンク)...」
  • link 21年6月20日
    すずき (11/02 13:22)
    「[読書一生分が93万円?] 目次: マンガ紹介書籍通販のhontoがこんなキャンペーンをやっています。honto読書一生分プレ...」
  • link 17年10月27日
    すずき (11/02 13:11)
    「[異世界&最強系漫画の種類] 目次: マンガ紹介少し前にアニメ化されて盛り上がって(おそらく負の方向に…)いた「...」
  • link 24年10月28日
    すずき (10/30 23:49)
    「[Linuxからリモートデスクトップ] 目次: Linux開発用のLinuxマシンの画面を見るにはいろいろな手段がありますが、...」
  • link 23年4月10日
    すずき (10/30 23:46)
    「[Linux - まとめリンク] 目次: Linux関係の深いまとめリンク。目次: RISC-V目次: ROCK64/ROCK...」
  • link 24年10月24日
    すずき (10/25 02:35)
    「[ONKYOからM-AUDIOのUSB DACへ] 目次: PCかれこれ10年以上(2013年3月16日の日記参照)活躍してく...」
  • link 24年7月25日
    すずき (10/25 02:24)
    「[OpenSBIを調べる - デバイスツリーの扱い(別方法)] 目次: LinuxOpenSBIのブート部分を調べます。Ope...」
  • link 24年8月7日
    すずき (10/25 02:23)
    「[Debian独自の挙動をするQEMUとbinfmt_misc] 目次: Linux前回はbinfmt_miscの使い方や動作...」
  • link 24年9月9日
    すずき (10/25 02:22)
    「[GDBの便利コマンド] 目次: LinuxGDBは便利ですが、少し使わないでいるとあっという間にコマンドを忘れます。便利&使...」
  • link 24年10月20日
    すずき (10/25 02:22)
    「[ゲームを買ったら遊びましょう2] 目次: ゲーム前回の振り返り(2022年5月13日の日記参照)から2年半経ちました。所持し...」
  • link 24年8月2日
    すずき (10/25 02:21)
    「[Debian on RISC-V] 目次: LinuxOpenSBI + Linuxの環境まで動いたので、次はLinuxのデ...」
  • link 24年8月6日
    すずき (10/25 02:21)
    「[他アーキテクチャ向けバイナリを実行する仕組みbinfmt_misc] 目次: LinuxRISC-V 64bit用の実行ファ...」
  • link 24年8月27日
    すずき (10/25 02:20)
    「[Milk-V Jupiterが届いた] 目次: RISC-VMilk-V Jupiterが届きました。お値段が非常に安かった...」
  • link 24年9月13日
    すずき (10/25 02:20)
    「[OpenSBIを調べる - OpenSBIとRISC-V ISA extensions] 目次: Linux今回はOpenS...」
  • link 24年10月11日
    すずき (10/25 02:19)
    「[企業のドメイン] 今の企業は公式サイトを持っていなほうが珍しいと思いますが、ドメイン名の使い方は各社でバラバラで面白いです。...」
  • link 24年10月21日
    すずき (10/25 02:18)
    「[OpenPilotを調べる - プロセス間通信msgqの仕組み] 目次: OpenPilot最近はOSSの運転支援ソフトウェ...」
  • link 24年10月6日
    すずき (10/25 02:11)
    「[OpenPilotを調べる - ビルドと実行] 目次: OpenPilot最近はOSSの運転支援ソフトウェアOpenPilo...」
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 www2.katsuster.net
RDFファイル RSS 1.0

最終更新: 11/04 15:17