page0053
の編集
http://osecpu.osask.jp/wiki/?page0053
[
トップ
] [
編集
|
差分
|
バックアップ
|
添付
|
リロード
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
-- 雛形とするページ --
BracketName
FormattingRules
FrontPage
Fulyn
Fulyn-v2
Fulyn_Samples
Help
InterWiki
InterWikiName
InterWikiSandBox
K
KOR_PIT8254
KWVM.NET
Liva
MANA
MenuBar
OSECPU_FPGA
PG_MANA
PHP
PukiWiki
PukiWiki/1.4
PukiWiki/1.4/Manual
PukiWiki/1.4/Manual/Plugin
PukiWiki/1.4/Manual/Plugin/A-D
PukiWiki/1.4/Manual/Plugin/E-G
PukiWiki/1.4/Manual/Plugin/H-K
PukiWiki/1.4/Manual/Plugin/L-N
PukiWiki/1.4/Manual/Plugin/O-R
PukiWiki/1.4/Manual/Plugin/S-U
PukiWiki/1.4/Manual/Plugin/V-Z
RecentDeleted
SandBox
WikiEngines
WikiName
WikiWikiWeb
YukiWiki
hikalium
hikarupsp
hikarupsp_ELCHNOS
hikarupsp_ELCHNOS_IDE
hikarupsp_FrontEndCode
hikarupsp_WebCPU-VM
hikarupsp_WebCPU-VM_internal
hikarupsp_study_hh4
impressions
impressions0000
jpag0000
jpag0001
jpag0002
jpag0003
jpag0004
jpag0005
lambdalice
mandel59
members
memo0000
memo0001
memo0002
memo0003
memo0004
memo0005
memo0006
memo0007
memo0008
memo0009
memo0010
osask
osecpu4android
page0000
page0001
page0002
page0003
page0004
page0005
page0006
page0007
page0008
page0009
page0010
page0011
page0012
page0013
page0014
page0015
page0016
page0017
page0018
page0019
page0020
page0021
page0022
page0023
page0024
page0025
page0026
page0027
page0028
page0029
page0030
page0031
page0032
page0033
page0034
page0035
page0036
page0037
page0038
page0039
page0040
page0041
page0042
page0043
page0044
page0045
page0046
page0047
page0048
page0049
page0050
page0051
page0052
page0053
page0054
page0055
page0056
page0057
page0058
page0059
page0060
page0061
page0062
page0063
page0064
page0065
page0066
page0067
page0068
page0069
page0070
page0071
page0072
page0073
page0074
page0075
page0076
page0077
page0078
page0079
page0080
page0081
page0082
page0083
page0084
page0085
page0086
page0087
page0088
page0089
page0090
page0091
page0092
page0093
page0094
page0095
page0096
page0097
page0098
page0099
page0100
page0101
page0102
page0103
page0104
page0105
page0106
page0107
page0108
page0109
pagenames
populars
seccamp2013
seccamp2014
seccamp2017
ttwilb
ttwilb-asmi
yao
* printfの%d的なAPIについて -(by [[K]], 2013.07.22) ** (0) はじめに -OSECPUは[[page0040]]で、もはや病的なほどにサイズにこだわっているのに、しかしまだprintfの%dみたいなものがなく、[[page0044]]の(4)ではputDecなどという関数まで作っています。 -しかし数字の表示なんて実に典型的でありふれた処理です。こんなに使用頻度の高いものをAPIとして提供しないのはなぜでしょう。それは[[page0040]]の考え方とは矛盾しているのではないでしょうか? ** (1) Kは10進数が嫌い -実は僕は10進数が嫌いです。こんな進数は人間の指がたまたま10本だったからで、それにはさしたる必然性がないのです。今、社会で10進数が標準的に使われているのは、単に歴史的経緯によってそうしているだけです。QWERTYキーボードと同じです。 -こんなくだらないものはいつか廃(すた)れると思います。だからそんなものをAPIに入れたくはありません。まあいつかといっても1000年後くらいになるかもしれないですが・・・。 -僕は2進数や4進数や16進数が好きです。これらの進数には必然性があります。特に16進数はもっとも便利な進数だと信じています。 ~ -こういう妙なこだわりがあるので、なかなか%d的なものをAPIに入れることができませんでした。 ** (2) 言い訳でしかない -しかしこれは実は言い訳でしかありません。というのは、上記論法によれば%dがない理由は説明できますが、OSECPUには%x的なものもないからです。 ~ -ということで、ver.0.62からは%d的な機能をAPIでサポートします!・・・しました。 -その結果、[[page0054]]の(4)の[4-1]のようなプログラムが34バイトで書けるようになりました。やったね! ** (3) 隠れた問題・・・それは可変長引数問題 -%d的なものを実装しようとすると、関数の可変長引数がほしくなります。ここではその話を書こうと思います。 ~ -まずOSECPUは本質的には可変長引数をサポートしていません。引数はレジスタ渡しで、しかも使えるレジスタはR30~R3Bまでです。P31~P3Bもありますが、とにかく整数を渡そうと思ったら12個までしか渡せません。 -これはいいのか、・・・一見するとよくない仕様のようにも見えます。GCCなどでは基本的にはスタック渡しで、引数が少ないときのみレジスタ渡し、みたいな感じになっています。・・・僕もこの仕様を決めるまでには相当に悩みました。 -僕の考えはこうです。 --大多数の関数は固定長引数で記述できる。 --あらかじめ引数の型と順番が分かっていれば、それらを短い機械語に割り当てることが可能になる(実際、OSECPUのAPI呼び出し用バイトコードは驚異的に短いです)。 --固定長であれば、レジスタ渡しの方が(特にOSECPUでは)効率がいい。 -ということで、まずは固定長引数関数をメインでサポートしました。 ~ -一方で、可変長引数のサポートも必要です。これをどうしたらいいのかを考えました。そして出た結論は、「配列のポインタとサイズを渡す」方法を作ることでした。・・・つまりこのタイプの関数は、P3xとR3xを一つずつ受け取けとる固定長引数の関数なのです。もちろんその引数の他にも、追加の固定長の引数をR3xやP3xで受け取ることができます。 -OSECPUでは配列を引数として渡したいときに、関数の引数リストの中に配列の要素も一緒に並べてしまうことができます。というか、文字列表示の 5 1 0 5 68 65 6C 6C 6F -などという記述はまさにこれを使っています。68 65 6C 6C 6F という5バイトの配列をスタック上に作って、それのポインタがP31に入り、これの文字長5がR31に入って、それで呼び出されているだけなのです。 -ここでは定数ばかりを配列に代入していますが、もちろんレジスタの値も入れられます。その自由度は普通の引数と何ら変わりありません。 -ここまでをまとめると、OSECPUでは可変長引数を本質的にはサポートしない代わりに、配列を引数に渡すときにその内容をインライン展開して記述できるようにしたのです。おかげで実質上は可変長引数があるのと同じになりました。 ~ -配列を渡すときに、インライン展開ではなくて、すでに作った配列のポインタと長さを渡したいこともあるでしょう。また、定数ばかりの配列なのか、変数も混ざっているのかで、バイトコードのエンコード方式も変えたいと思いました。 -ということで、配列を渡すときにはまずモード番号を記述します。上記の例はモード0を指定しています。・・・モード1なら、配列の値として負の値やレジスタの値も指定できます。モード2なら、既存の配列のポインタと長さを指定できます。モード3なら長さ指定をする必要はなく、終端コード(この場合は0)で終わるだけでいいです。 --このモード3を指定していたとしても、結局長さはJITコンパイル時には決定できるので(モード3は配列のインライン展開モードなので)、関数に渡る配列長はただの定数です。つまり実行時にstrlen的なことをしているわけではありませんし、スタック内のデータに終端コードは書き込まれていません。 -他にもモードはありますが、まあきりがないのでこれくらいにしておきます。 -このモード方式に到達するまでも、いろいろ悩みました。モード番号を書けば、それだけで0.5バイトが必要になります。モード番号など書かずにもっとも汎用性のあるモードを一つ作って、それだけを使わせるほうがいいのではないかとも思いました。そうすれば0.5バイトは節約できますし、JITコンパイラも単純化できます。 -しかし結局は、モード番号制にしました。今ではこれが一番効率が良いと確信しています。 ~ -この節の冒頭で、%dのためには可変長引数が必要だとか書きましたが、まあこんなわけで、可変長引数的なものはすでに完成していたのです。だから実はそんなことは問題ではないのです。 -しかし・・・%d的なことをしようと思ったら、今の文字列に加えて他に可変長引数が必要です。文字列の後に足してもいいですが、文字列はUInt8の配列でしかないので、整数変数32ビットを入れられません。8ビットずつ区切って無理やり入れますか?それはうまい方法と言えるのでしょうか?これが悩ましいのです。 -それでどうしたのかと言えば、配列引数を2つとれるようにしました。まあ仕様上は3つでも4つでもいいのですが、現状の実装では2つまでをサポートしています。文字列はUInt8の配列ですが、残りの引数の可変長引数はSInt32の配列です。ここに表示したい値を入れるのはもちろんのこと、%4dの4の部分の数字や、進法指定、+や0などのフラグ指定などを全部入れました。こうすることで、関数側は文字列の中に埋まった数値をパースしてデコードする必要がありません。また文字列の中で10を指定すると2バイトも食いますが、SInt32の配列の中なら1バイトで済みます。つまりこの仕様はアプリの実行ファイルを短くする役にも立つわけです。 -今回は%d的なものしか配慮していませんが、将来は%fや%sや%pのサポートも必要になると思います。その時は、UInt8, SInt32, Flt64, UInt8, VPtrの5配列版を作ろうと思っています。こうやってAPIが増えていくのはちょっと良くないと思っているので、次に追加するときまでにはヌル配列指定を可能にして、APIの乱発を食い止めたいと思います。 --整数の表示は利用頻度が高そうで、そうであれば汎用的なものひとつだけではなく専用的なものがあったほうがいいのではないかと思うので、これはこれでいいと思っています。・・・まあjunkApiなのでそもそもそんなに気にしなくてもいいかもしれませんが。 * こめんと欄 #comment
タイムスタンプを変更しない
* printfの%d的なAPIについて -(by [[K]], 2013.07.22) ** (0) はじめに -OSECPUは[[page0040]]で、もはや病的なほどにサイズにこだわっているのに、しかしまだprintfの%dみたいなものがなく、[[page0044]]の(4)ではputDecなどという関数まで作っています。 -しかし数字の表示なんて実に典型的でありふれた処理です。こんなに使用頻度の高いものをAPIとして提供しないのはなぜでしょう。それは[[page0040]]の考え方とは矛盾しているのではないでしょうか? ** (1) Kは10進数が嫌い -実は僕は10進数が嫌いです。こんな進数は人間の指がたまたま10本だったからで、それにはさしたる必然性がないのです。今、社会で10進数が標準的に使われているのは、単に歴史的経緯によってそうしているだけです。QWERTYキーボードと同じです。 -こんなくだらないものはいつか廃(すた)れると思います。だからそんなものをAPIに入れたくはありません。まあいつかといっても1000年後くらいになるかもしれないですが・・・。 -僕は2進数や4進数や16進数が好きです。これらの進数には必然性があります。特に16進数はもっとも便利な進数だと信じています。 ~ -こういう妙なこだわりがあるので、なかなか%d的なものをAPIに入れることができませんでした。 ** (2) 言い訳でしかない -しかしこれは実は言い訳でしかありません。というのは、上記論法によれば%dがない理由は説明できますが、OSECPUには%x的なものもないからです。 ~ -ということで、ver.0.62からは%d的な機能をAPIでサポートします!・・・しました。 -その結果、[[page0054]]の(4)の[4-1]のようなプログラムが34バイトで書けるようになりました。やったね! ** (3) 隠れた問題・・・それは可変長引数問題 -%d的なものを実装しようとすると、関数の可変長引数がほしくなります。ここではその話を書こうと思います。 ~ -まずOSECPUは本質的には可変長引数をサポートしていません。引数はレジスタ渡しで、しかも使えるレジスタはR30~R3Bまでです。P31~P3Bもありますが、とにかく整数を渡そうと思ったら12個までしか渡せません。 -これはいいのか、・・・一見するとよくない仕様のようにも見えます。GCCなどでは基本的にはスタック渡しで、引数が少ないときのみレジスタ渡し、みたいな感じになっています。・・・僕もこの仕様を決めるまでには相当に悩みました。 -僕の考えはこうです。 --大多数の関数は固定長引数で記述できる。 --あらかじめ引数の型と順番が分かっていれば、それらを短い機械語に割り当てることが可能になる(実際、OSECPUのAPI呼び出し用バイトコードは驚異的に短いです)。 --固定長であれば、レジスタ渡しの方が(特にOSECPUでは)効率がいい。 -ということで、まずは固定長引数関数をメインでサポートしました。 ~ -一方で、可変長引数のサポートも必要です。これをどうしたらいいのかを考えました。そして出た結論は、「配列のポインタとサイズを渡す」方法を作ることでした。・・・つまりこのタイプの関数は、P3xとR3xを一つずつ受け取けとる固定長引数の関数なのです。もちろんその引数の他にも、追加の固定長の引数をR3xやP3xで受け取ることができます。 -OSECPUでは配列を引数として渡したいときに、関数の引数リストの中に配列の要素も一緒に並べてしまうことができます。というか、文字列表示の 5 1 0 5 68 65 6C 6C 6F -などという記述はまさにこれを使っています。68 65 6C 6C 6F という5バイトの配列をスタック上に作って、それのポインタがP31に入り、これの文字長5がR31に入って、それで呼び出されているだけなのです。 -ここでは定数ばかりを配列に代入していますが、もちろんレジスタの値も入れられます。その自由度は普通の引数と何ら変わりありません。 -ここまでをまとめると、OSECPUでは可変長引数を本質的にはサポートしない代わりに、配列を引数に渡すときにその内容をインライン展開して記述できるようにしたのです。おかげで実質上は可変長引数があるのと同じになりました。 ~ -配列を渡すときに、インライン展開ではなくて、すでに作った配列のポインタと長さを渡したいこともあるでしょう。また、定数ばかりの配列なのか、変数も混ざっているのかで、バイトコードのエンコード方式も変えたいと思いました。 -ということで、配列を渡すときにはまずモード番号を記述します。上記の例はモード0を指定しています。・・・モード1なら、配列の値として負の値やレジスタの値も指定できます。モード2なら、既存の配列のポインタと長さを指定できます。モード3なら長さ指定をする必要はなく、終端コード(この場合は0)で終わるだけでいいです。 --このモード3を指定していたとしても、結局長さはJITコンパイル時には決定できるので(モード3は配列のインライン展開モードなので)、関数に渡る配列長はただの定数です。つまり実行時にstrlen的なことをしているわけではありませんし、スタック内のデータに終端コードは書き込まれていません。 -他にもモードはありますが、まあきりがないのでこれくらいにしておきます。 -このモード方式に到達するまでも、いろいろ悩みました。モード番号を書けば、それだけで0.5バイトが必要になります。モード番号など書かずにもっとも汎用性のあるモードを一つ作って、それだけを使わせるほうがいいのではないかとも思いました。そうすれば0.5バイトは節約できますし、JITコンパイラも単純化できます。 -しかし結局は、モード番号制にしました。今ではこれが一番効率が良いと確信しています。 ~ -この節の冒頭で、%dのためには可変長引数が必要だとか書きましたが、まあこんなわけで、可変長引数的なものはすでに完成していたのです。だから実はそんなことは問題ではないのです。 -しかし・・・%d的なことをしようと思ったら、今の文字列に加えて他に可変長引数が必要です。文字列の後に足してもいいですが、文字列はUInt8の配列でしかないので、整数変数32ビットを入れられません。8ビットずつ区切って無理やり入れますか?それはうまい方法と言えるのでしょうか?これが悩ましいのです。 -それでどうしたのかと言えば、配列引数を2つとれるようにしました。まあ仕様上は3つでも4つでもいいのですが、現状の実装では2つまでをサポートしています。文字列はUInt8の配列ですが、残りの引数の可変長引数はSInt32の配列です。ここに表示したい値を入れるのはもちろんのこと、%4dの4の部分の数字や、進法指定、+や0などのフラグ指定などを全部入れました。こうすることで、関数側は文字列の中に埋まった数値をパースしてデコードする必要がありません。また文字列の中で10を指定すると2バイトも食いますが、SInt32の配列の中なら1バイトで済みます。つまりこの仕様はアプリの実行ファイルを短くする役にも立つわけです。 -今回は%d的なものしか配慮していませんが、将来は%fや%sや%pのサポートも必要になると思います。その時は、UInt8, SInt32, Flt64, UInt8, VPtrの5配列版を作ろうと思っています。こうやってAPIが増えていくのはちょっと良くないと思っているので、次に追加するときまでにはヌル配列指定を可能にして、APIの乱発を食い止めたいと思います。 --整数の表示は利用頻度が高そうで、そうであれば汎用的なものひとつだけではなく専用的なものがあったほうがいいのではないかと思うので、これはこれでいいと思っています。・・・まあjunkApiなのでそもそもそんなに気にしなくてもいいかもしれませんが。 * こめんと欄 #comment
テキスト整形のルールを表示する