xbyak

x86向けのJITアセンブラとして、XBYAKというのが公開されていた。
http://homepage1.nifty.com/herumi/soft/xbyak.html

今までC++で無駄に最適化をしている時に実行時最適化も出来ればもうちょっと速くなるのに…と心残りだった。sourceforgeで公開してたSoftWireは自分がDLしないうちに買われて未公開になってしまったし、googleで動的コード生成とかについて検索してもあまり判り易いのは無かったし、で諦めていたけど道具が公開されたので手間を掛ければ常人でももしかしたら…。

CとかC++でここらへんの技術が採用されない理由を考えてみる。

  1. 静的な流れを壊してしまうのでとても既存の言語仕様にまともな形で組み込めない?(JavaのようにVMに実行コードの生成を任せる高級言語ならば、そこは一般ユーザーは気にしないで良いんだろう…。)
  2. 細かな実行の制御を行おうとすると特定のアーキテクチャに依存してしまう。
  3. そもそも需要が極端に少ない。
  4. あからさまに最適化の落とし穴が見え見え。

あと自己書き換えプログラムは、実行コードのキャッシュと矛盾してしまうからか、現実的では無いという事を聞いたり読んだりした事はあるけれど、それと動的コード生成は違うだろうから多分そこは大丈夫かな?怖いよー。

しかしアセンブリコードを生成させる命令を書こうとしてもアセンブリを日頃書いていないのでさっぱり。初心者なので補助輪着けた自転車に乗るようにしよう…。

class TestFunc : public Xbyak::CodeGenerator
{
public:
	TestFunc(int y)
	{
		mov(eax, ptr[esp+4]);
		add(eax, y);
		ret();
	}
	int (*get() const)(int) { return (int (*)(int))getCode(); }
};


template <typename FPT>
class NewbieCodeGenerator : public Xbyak::CodeGenerator
{
public:
	typedef FPT fp_t;

	NewbieCodeGenerator()
	{
	}
	
	fp_t getCode() { return (fp_t) __super::getCode(); }
	
protected:
	
	void store(size_t stackSize)
	{
		push(ebp);
		mov(ebp, esp);
		sub(esp, stackSize);
	}
	
	void restore()
	{
		mov(esp, ebp);
		pop(ebp);
	}

	Xbyak::Address argAddressStack(size_t idx)
	{
		return ptr[esp + 4 * (1 + idx)];
	}
	
	Xbyak::Address argAddressBase(size_t idx)
	{
		return ptr[ebp + 4 * (2 + idx)];
	}

	Xbyak::Address localAddressBase(size_t idx)
	{
		return ptr[ebp - 4 * (1 + idx)];
	}
};

class TestFunc2 : public NewbieCodeGenerator<int (*) (int)>
{
public:
	TestFunc2(int a)
	{
#if 0
		store(4 * 10);
		
		mov(localAddressBase(0), 1);
		mov(localAddressBase(1), -1);
		mov(eax, argAddressBase(0));
		add(eax, a);
		add(eax, localAddressBase(0));
		add(eax, localAddressBase(1));
		
		restore();
#else
		mov(eax, argAddressStack(0));
		add(eax, a);

#endif
		ret();
	}

};

pushやpopする度にespからのoffsetを調整する手もあるけれど、そもそも細かいのが見えてしまう世界なので、そこにいる限りそこから逃げて忘れる事は出来ないのかもしれない…。