From 1ea60f3a96a55081ef3f89d6dd8a75274ac39918 Mon Sep 17 00:00:00 2001 From: Dirk Steinke Date: Tue, 22 Jul 2014 01:30:34 +0200 Subject: [PATCH] A first step towards construction of functions. A lot of work went into x86_xx_insinfo.lcpp which i need when splitting an instruction stream into single instructions. Fixed some instruction definitions in inslist.ltxt. Cannot link yet. Once this is working, i can actually work in the innards (data flow analysis, code gen, etc.) again. --- .gitignore | 2 + include/jitcs_function.h | 5 +- include/jitcs_instructionstream.h | 1 + include/jitcs_machine.h | 4 ++ include/jitcs_x86_xx_cons.lh | 4 +- include/jitcs_x86_xx_regs.lh | 13 ++-- makefile | 19 ++++- src/data/x86_inslist.ltxt | 9 +-- src/jitcs_int_bblock_impl.h | 2 + src/jitcs_int_function_impl.h | 20 ++++-- src/src/bblock.cpp | 3 + src/src/bblock_impl.cpp | 41 ++++++++++- src/src/function.cpp | 11 ++- src/src/function_impl.cpp | 58 ++++++++++++---- src/src/machine.cpp | 10 ++- src/src/virtualregister.cpp | 8 +++ src/x86/jitcs_int_x86_xx_regs.lh | 16 ++--- src/x86/src/x86_xx_insinfo.lcpp | 143 ++++++++++++++++++++++++++++++++++++++ src/x86/src/x86_xx_machine.lcpp | 2 +- src/x86/src/x86_xx_regs.lcpp | 22 +++--- tests/test_simplefunction.cpp | 78 +++++++++++++++++++++ tools/x86_inslist2data.lua | 2 + 22 files changed, 410 insertions(+), 63 deletions(-) create mode 100644 src/x86/src/x86_xx_insinfo.lcpp create mode 100644 tests/test_simplefunction.cpp diff --git a/.gitignore b/.gitignore index 484c444..e83b244 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,7 @@ src/x86/src/x86_32_machine.cpp src/x86/src/x86_64_machine.cpp src/x86/src/x86_32_regs.cpp src/x86/src/x86_64_regs.cpp +src/x86/src/x86_32_insinfo.cpp +src/x86/src/x86_64_insinfo.cpp src/data/x86_ins*.dat err.log diff --git a/include/jitcs_function.h b/include/jitcs_function.h index 5c66223..63ce3ee 100644 --- a/include/jitcs_function.h +++ b/include/jitcs_function.h @@ -39,8 +39,9 @@ public: Enumerator enumerateBasicBlocks(); //Enumerator enumerateVirtualRegisters(); std::shared_ptr getCallingConvention() const; - //RefOrNull getArgumentRegister(uint n); - //RefOrNull getResultRegister(uint n); + Ref getArgumentRegister(uint n, RegClassId); + Ref getResultRegister(uint n, RegClassId); + Ref createRegister(RegClassId, int logSz = 0); public: //void check(); diff --git a/include/jitcs_instructionstream.h b/include/jitcs_instructionstream.h index 5bdc73d..8b88cee 100644 --- a/include/jitcs_instructionstream.h +++ b/include/jitcs_instructionstream.h @@ -43,6 +43,7 @@ struct InstructionStreamBuffer : InstructionStream { InstructionStreamBuffer() = default; void start(RefOrNull block) { bb = block; init(&originalBuffer[0], INSSZ2); } + void start(Ref block) { bb._ptr = block._ptr; init(&originalBuffer[0], INSSZ2); } void end() { _flush(); bb = nullptr; } protected: diff --git a/include/jitcs_machine.h b/include/jitcs_machine.h index 2d7cc3f..092c00e 100644 --- a/include/jitcs_machine.h +++ b/include/jitcs_machine.h @@ -42,6 +42,7 @@ private: public: CPUInfo cpu; + // virtual ResId getResOfReg(RegId r) const = 0; virtual RegClassId getRegClassOfReg(RegId r) const = 0; virtual ResClassId getResClassOfReg(RegId r) const = 0; @@ -58,6 +59,9 @@ public: virtual ResClassId getResClassCount() const = 0; virtual u32 getResIndexOfResClass(ResClassId r) const = 0; + // + virtual size_t getInsIdInfo(InsId) const = 0; + //u32 numRes; //u8 numRegClass, numResClass; diff --git a/include/jitcs_x86_xx_cons.lh b/include/jitcs_x86_xx_cons.lh index e68bed5..f420615 100644 --- a/include/jitcs_x86_xx_cons.lh +++ b/include/jitcs_x86_xx_cons.lh @@ -46,11 +46,11 @@ namespace x86_%(N) { typedef MemRef Mem256Ref; typedef MemRef Mem512Ref; - extern const u8 ArrayInsClassSizes[x86_%(N)::IC_Count - x86_%(N)::IC_Invalid - 1]; + extern const u16 ArrayInsClassInfo[x86_%(N)::IC_Count - x86_%(N)::IC_Invalid - 1]; inline uint GetInsSize(InsId id) { u32 cid = (id >> IC_SubBits); assert(cid > x86_%(N)::IC_Invalid && cid < x86_%(N)::IC_Count); - return ArrayInsClassSizes[cid - x86_%(N)::IC_Invalid - 1]; + return ArrayInsClassInfo[cid - x86_%(N)::IC_Invalid - 1] >> 12; } template struct InsClassSizeCT {}; diff --git a/include/jitcs_x86_xx_regs.lh b/include/jitcs_x86_xx_regs.lh index 2f469b8..40aedfe 100644 --- a/include/jitcs_x86_xx_regs.lh +++ b/include/jitcs_x86_xx_regs.lh @@ -34,6 +34,7 @@ namespace jitcs { struct VirtualRegister; +RegClassId GetRegClass(const VirtualRegister* r); namespace x86_%(N) { /*| local n2c = {} @@ -59,15 +60,15 @@ namespace x86_%(N) { /*| refclass_filtered[#refclass_filtered + 1] = cl /*| end /*| --*/ -static const RegClassId RC_Count = static_cast(%(#refclass_filtered)); +static const RegClassId RCL_Count = static_cast(%(#refclass_filtered)); // special regs #define RCLID(ID) static_cast((ID)) /*| for l,cl in ipairs(refclass_filtered) do -static const RegClassId RC_%(cl.name) = RCLID(%l); +static const RegClassId RCL_%(cl.name) = RCLID(%l); /*| end /*| for l,cl in pred_ipairs(data.refclassaliases,isaN) do -static const RegClassId RC_%(cl.name) = RC_%(cl.dest); +static const RegClassId RCL_%(cl.name) = RCL_%(cl.dest); /*| end /*| --*/ #undef RCLID @@ -157,17 +158,15 @@ static const RegLookup<_fixedRegister%(N==32 and v2nn[v.dest].x32 or v2nn[v.dest /*| (n2c[v].x64 or not n2c[v].x32) and t64) /*| end /*| for k,v in ipairs(cl.superrefclasses or {}) do -/*| local t = "rc == RC_" .. v +/*| local t = "rc == RCL_" .. v /*| test2 = (test2 or "") .. " || " /*| test2 = test2 .. testrn((n2c[v].x32 or not n2c[v].x64) and t, (n2c[v].x64 or not n2c[v].x32) and t) /*| end inline bool Is%(cl.name)(RegId r) { return %(test or ""); } -inline bool Is%(cl.name)(RegClassId rc) { return rc == RC_%(cl.name)%(test2 or ""); } +inline bool Is%(cl.name)(RegClassId rc) { return rc == RCL_%(cl.name)%(test2 or ""); } /*| end /*| --*/ -RegClassId GetRegClass(const VirtualRegister* r); - /*| for l,cl in pred_ipairs(data.refclasses,isaN) do struct %(cl.name)Ref : public Ref { %(cl.name)Ref() = delete; diff --git a/makefile b/makefile index 4753f60..d3282f7 100644 --- a/makefile +++ b/makefile @@ -9,9 +9,11 @@ SRC_SRC = cpu.cpp dumper.cpp tmpalloc.cpp memmgr.cpp bblock.cpp function.cpp cal bblock_impl.cpp function_impl.cpp callingconvention_impl.cpp spillslotinfo.cpp \ host.cpp machine.cpp virtualregister.cpp SRC_X86 = x86_32_callingconvention.cpp x86_64_callingconvention.cpp \ - x86_32_machine.cpp x86_64_machine.cpp x86_32_regs.cpp x86_64_regs.cpp + x86_32_machine.cpp x86_64_machine.cpp x86_32_regs.cpp x86_64_regs.cpp \ + x86_32_insinfo.cpp x86_64_insinfo.cpp SRC_UNITTEST = test_unittest.cpp test_main.cpp test_fnctypeinfo.cpp \ - test_adt_range.cpp test_adt_slice.cpp test_callingconvention.cpp + test_adt_range.cpp test_adt_slice.cpp test_callingconvention.cpp \ + test_simplefunction.cpp PREFIXES_LIBSRC = dbg32_ rel32_ dbg64_ rel64_ PREFIXES_TESTSRC = test32_ test64_ OBJDIR = _objs @@ -105,6 +107,12 @@ src/x86/src/x86_32_regs.cpp : src/x86/src/x86_xx_regs.lcpp src/data/x86_reglist. src/x86/src/x86_64_regs.cpp : src/x86/src/x86_xx_regs.lcpp src/data/x86_reglist.dat \ tools/template2header.lua $(LUA) tools/template2header.lua $< 64 $@ +src/x86/src/x86_32_insinfo.cpp : src/x86/src/x86_xx_insinfo.lcpp src/data/x86_reglist.dat \ + tools/template2header.lua + $(LUA) tools/template2header.lua $< 32 $@ +src/x86/src/x86_64_insinfo.cpp : src/x86/src/x86_xx_insinfo.lcpp src/data/x86_reglist.dat \ + tools/template2header.lua + $(LUA) tools/template2header.lua $< 64 $@ src/data/x86_inslist.dat : src/data/x86_inslist.ltxt tools/x86_inslist2data.lua $(LUA) tools/x86_inslist2data.lua $< $@ @@ -185,6 +193,10 @@ $(addsuffix x86_32_regs.o, $(OBJPREFIX_X86)): \ src/x86/jitcs_int_x86_32_regs.h $(addsuffix x86_64_regs.o, $(OBJPREFIX_X86)): \ src/x86/jitcs_int_x86_64_regs.h +$(addsuffix x86_32_insinfo.o, $(OBJPREFIX_X86)): \ + include/jitcs_x86_32_insids.h +$(addsuffix x86_64_insinfo.o, $(OBJPREFIX_X86)): \ + include/jitcs_x86_64_insids.h $(addsuffix main.o, $(OBJPREFIX_TEST)): \ @@ -200,6 +212,9 @@ $(addsuffix adt_slice.o, $(OBJPREFIX_TEST)): \ $(addsuffix callingconvention.o, $(OBJPREFIX_TEST)): \ include/jitcs_base.h include/jitcs_callingconvention.h \ include/jitcs_x86_32_machine.h include/jitcs_x86_64_machine.h +$(addsuffix simplefunction.o, $(OBJPREFIX_TEST)): \ + include/jitcs_base.h include/jitcs_callingconvention.h \ + include/jitcs_instructionstream.h include/jitcs.h $(OBJDIR)/dbg32_src_%.o : src/src/%.cpp $(CC) -o $@ -c -I ./src $(CFLAGS) $(CFLAGS_DBG32) $< diff --git a/src/data/x86_inslist.ltxt b/src/data/x86_inslist.ltxt index 2654303..74b3243 100644 --- a/src/data/x86_inslist.ltxt +++ b/src/data/x86_inslist.ltxt @@ -106,7 +106,7 @@ TEST_%(RNM(rm,v))%(RN(v)) | end CRC32_W%(RNMN(rm,v)) {isa %ISA sse42; ops GR32 dst/io, %RRM src/i; flags %RMEM; - pref f2; rex %rm %W dst src; extopcode 0f38; coding !parsub(%(0xf0+R16)) !RRM%(RM)($dst,$src); + pref %(P)f2; rex %rm %W dst src; extopcode 0f38; coding !parsub(%(0xf0+R16)) !RRM%(RM)($dst,$src); fold CRC32_W%(MN(v))} CMPXCHG_%(RNM(rm,v))%(RN(v))_%(EAX(v)) {isa %ISA; ops %RRM dst/%(rrm(rm,"io","i")), %R src/io, %R{%(EAX(v))} cmp/i; flags %RMEM wflags; @@ -225,11 +225,11 @@ POPCNT_%(RN(v))%(RNM(rm,v)) | for l,w in ipairs{8,16} do MOVZX_%(RN(v))%(RNMN(rm,w)) //= MOVX_%(RN(v))%(RNMN(rm,w)).6 {isa %ISA; ops %R dst/o, %(grm(rm,w)) src/i; flags %RMEM; - rex %rm %W dst src; extopcode 0f; coding !parsub(%(0xb6+R16)) !RRM%(RM)($dst,$src); + rex %rm %W dst src; extopcode 0f; coding !parsub(%(0xb6+w/8)) !RRM%(RM)($dst,$src); fold MOVZX_%(RN(v))%(MN(w))} MOVSX_%(RN(v))%(RNMN(rm,w)) //= MOVX_%(RN(v))%(RNMN(rm,w)).14 {isa %ISA; ops %R dst/o, %(grm(rm,w)) src/i; flags %RMEM; - rex %rm %W dst src; extopcode 0f; coding !parsub(%(0xbe+R16)) !RRM%(RM)($dst,$src); + rex %rm %W dst src; extopcode 0f; coding !parsub(%(0xbe+w/8)) !RRM%(RM)($dst,$src); fold MOVSX_%(RN(v))%(MN(w))} | end ANDN_%(RN(v))%(RN(v))%(RNM(rm,v)) @@ -1026,9 +1026,6 @@ PBLENDVB_%(XN(w))%(X(w))%(XNM(w))_XMM0 {isa sse41; ops %VR dst/io, %VRM src/i, %VR{xmm0} msk/i; flags %RMEM; pref 66; %(VEX_DS(w)); extopcode 0f38; coding !parsub(0x10) !RRM%(RM)($dst,$src); fold PBLENDVB_%(XN(w))%(X(w))M_XMM0} -MASKMOVDQU_%(XN(w))%(X(w))%(XNM(w))_XMM0 - {isa sse41; ops %VR dst/io, %VRM src/i, %VR{xmm0} msk/i; flags %RMEM; - pref 66; %(VEX_DS(w)); extopcode 0f38; coding !parsub(0x10) !RRM%(RM)($dst,$src)} | else -- avx | for m,u in ipairs{{"B",0x78,8}, {"W",0x79,16}, {"D",0x58,32}, {"Q",0x59,64}} do VPBROADCAST%(u[1])_%(XN(w))%(XMN(w,u[3])) diff --git a/src/jitcs_int_bblock_impl.h b/src/jitcs_int_bblock_impl.h index c4f7185..eeb8ee8 100644 --- a/src/jitcs_int_bblock_impl.h +++ b/src/jitcs_int_bblock_impl.h @@ -19,6 +19,7 @@ class TempAllocator; class BasicBlockImpl { public: + // TODO: use structures that use TempAllocator typedef std::vector BasicBlockList; typedef std::vector InstructionList; @@ -103,6 +104,7 @@ private: BasicBlockList _successors, _predecessors; BBId _bbId; RefOrNull _bbFallThruFrom, _bbFallThruTo; + bool _hasCFIns; }; //inline bool evm::NextData::isRegDead(BBlock* bb, ResId res) const { // return isRegDead() || (isRegDeadOrLiveOut() && !bb->getLiveOut().test(res.id)); diff --git a/src/jitcs_int_function_impl.h b/src/jitcs_int_function_impl.h index 534fe1d..9ac7e11 100644 --- a/src/jitcs_int_function_impl.h +++ b/src/jitcs_int_function_impl.h @@ -9,6 +9,7 @@ #include "jitcs_adt_range.h" #include "jitcs_adt_ref.h" +#include "jitcs_adt_refcounter.h" #include "jitcs_base.h" #include "jitcs_ids.h" #include "jitcs_memmgr.h" @@ -17,8 +18,10 @@ namespace jitcs { class BasicBlockImpl; class CallingConvention; +class IMachineInfo; class MachineDumper; class TempAllocator; +struct VirtualRegister; //struct XFragmentList; //class BBlockClusterMap; @@ -37,7 +40,7 @@ public: // typedef ConstRange const_vreg_range; public: - FunctionImpl(TempAllocator& ins, const std::shared_ptr& cc); + FunctionImpl(RefCounter& ins, const std::shared_ptr& cc); ~FunctionImpl(); size_t bbs_size() const { return _bblocks.size(); } @@ -69,8 +72,11 @@ public: //void check(); //void clean(); void dump(MachineDumper&) const; - std::shared_ptr - getCallingConvention() const; + std::shared_ptr getCallingConvention() const; + + Ref getArgumentRegister(uint n, RegClassId); + Ref getResultRegister(uint n, RegClassId); + Ref createRegister(RegClassId, int logSz = 0); //VMMemory::CodeDataArea generate(VMMemory&, bool dump); @@ -85,7 +91,7 @@ public: //bool needsDefinitelyFramePointer() const; public: - TempAllocator& getAllocator() const { return _allocator; } + TempAllocator& getAllocator() const { return *_allocator._ptr; } Ref getStartBlock(); @@ -138,12 +144,14 @@ protected: private: //void _tryToAllocateXFragmentCluster(XFragmentList const&); + void _prepareArgumentAndResultRegisterSpace(); private: - TempAllocator& _allocator; + RefCounter _allocator; std::shared_ptr _cc; + RefCounter _mi; std::vector _bblocks; -// std::vector _vregs; + std::vector _parregs, _vregs; //std::vector< std::vector > _tempvregs; //struct FrameInfo { // VRegRef reg; diff --git a/src/src/bblock.cpp b/src/src/bblock.cpp index 5d65589..31f591a 100644 --- a/src/src/bblock.cpp +++ b/src/src/bblock.cpp @@ -67,3 +67,6 @@ void jitcs::BasicBlock::dump(MachineDumper& d) const { size_t jitcs::BasicBlock::append(iptr* p, size_t N) { _ToImpl(this)->append(p, N); } +size_t jitcs::BasicBlock::append_copy(iptr const* p, size_t N) { + _ToImpl(this)->append_copy(p, N); +} diff --git a/src/src/bblock_impl.cpp b/src/src/bblock_impl.cpp index 552d50c..a9dc58d 100644 --- a/src/src/bblock_impl.cpp +++ b/src/src/bblock_impl.cpp @@ -1,14 +1,19 @@ #include "jitcs_int_bblock_impl.h" #include "jitcs_int_function_impl.h" #include "jitcs_dumper.h" +#include "jitcs_tmpalloc.h" +#include "jitcs_machine.h" +#include "jitcs_callingconvention.h" #include +#include jitcs::BasicBlockImpl::BasicBlockImpl(FunctionImpl& f, BBId id) : _bbId(id) , _fnc(f) , _bbFallThruFrom(nullptr) , _bbFallThruTo(nullptr) - , _alloc(f.getAllocator()) { + , _alloc(f.getAllocator()) + , _hasCFIns(false) { } void jitcs::BasicBlockImpl::BuildEdge(BasicBlockImpl* fromBB, BasicBlockImpl* toBB, bool isFallthru) { assert(fromBB && toBB); @@ -52,3 +57,37 @@ void jitcs::BasicBlockImpl::dump(MachineDumper& o) const { o.write("\n"); } } +size_t jitcs::BasicBlockImpl::append_copy(iptr const *p, size_t N) { + iptr* data = _alloc.allocTypedArray(N); + memcpy(data, p, sizeof(iptr) * N); + return append(data, N); +} +size_t jitcs::BasicBlockImpl::append(iptr* p, size_t N) { + const size_t INSN = 16; + Instruction* insblock[INSN]; + size_t inscnt = 0; + size_t instotal = 0; + RefCounter mi = _fnc.getCallingConvention()->getMachineInfo(); + while (N > 0) { + assert(!_hasCFIns); + size_t result = mi->getInsIdInfo(static_cast(*p)); + assert((result & 1) == 0); + // TODO: consider variable length instructions! + size_t n = result >> 2; + assert(n <= N); + _hasCFIns = (result & 2) != 0; + if (inscnt == INSN) { + _listOfIns.insert(_listOfIns.end(), insblock, insblock + INSN); + instotal += INSN; + inscnt = 0; + } + insblock[inscnt++] = reinterpret_cast(p); + p += n; + N -= n; + } + if (inscnt > 0) { + _listOfIns.insert(_listOfIns.end(), insblock, insblock + inscnt); + instotal += inscnt; + } + return instotal; +} diff --git a/src/src/function.cpp b/src/src/function.cpp index 1470978..9d4d523 100644 --- a/src/src/function.cpp +++ b/src/src/function.cpp @@ -58,8 +58,15 @@ std::shared_ptr jitcs::Function::getCallingConvention() const { return _ToImpl(this)->getCallingConvention(); } - //RefOrNull getArgumentRegister(uint n); - //RefOrNull getResultRegister(uint n); +jitcs::Ref jitcs::Function::getArgumentRegister(uint n, RegClassId rc) { + return _ToImpl(this)->getArgumentRegister(n, rc); +} +jitcs::Ref jitcs::Function::getResultRegister(uint n, RegClassId rc) { + return _ToImpl(this)->getResultRegister(n, rc); +} +jitcs::Ref jitcs::Function::createRegister(RegClassId rc, int logSz) { + return _ToImpl(this)->createRegister(rc, logSz); +} //void check(); //void clean(); diff --git a/src/src/function_impl.cpp b/src/src/function_impl.cpp index a83bb26..e738d15 100644 --- a/src/src/function_impl.cpp +++ b/src/src/function_impl.cpp @@ -2,13 +2,18 @@ #include "jitcs_int_bblock_impl.h" #include "jitcs_callingconvention.h" #include "jitcs_dumper.h" +#include "jitcs_machine.h" #include "jitcs_tmpalloc.h" +#include "jitcs_int_virtualregister.h" -jitcs::FunctionImpl::FunctionImpl(TempAllocator& ins, const std::shared_ptr& cc) +jitcs::FunctionImpl::FunctionImpl + (RefCounter& ins, + const std::shared_ptr& cc) : _allocator(ins) //, _m(M_Construct) //, _frameInfoCnt(2) - , _cc(cc) { + , _cc(cc) + , _mi(cc->getMachineInfo()) { // create vregs for parameters and results // ins.setAlignment(16); @@ -53,10 +58,48 @@ jitcs::Ref jitcs::FunctionImpl::getStartBlock() { } jitcs::Ref jitcs::FunctionImpl::createBasicBlock() { + // TODO: allocate from TempAllocator BasicBlockImpl* bb = new BasicBlockImpl(*this, BBId(_bblocks.size())); _bblocks.push_back(bb); return bb; } +void jitcs::FunctionImpl::_prepareArgumentAndResultRegisterSpace() { + _parregs.resize(((_cc->getResultCount() + _cc->getParamCount())|1)); + for (auto i = _parregs.begin(), e = _parregs.end(); i != e; ++i) + *i = nullptr; +} + +jitcs::Ref jitcs::FunctionImpl::getArgumentRegister(uint n, RegClassId rc) { + assert(_parregs.size() == 0 || _parregs.size() >= (_cc->getResultCount() + _cc->getParamCount())); + assert(n < _cc->getParamCount()); + if (_parregs.size() == 0) + _prepareArgumentAndResultRegisterSpace(); + jitcs::VirtualRegister* &cell = _parregs[_cc->getResultCount() + n]; + if (cell == nullptr) { + cell = createRegister(rc)._ptr; + } + assert(cell->regclass == rc); + return cell; +} +jitcs::Ref jitcs::FunctionImpl::getResultRegister(uint n, RegClassId rc) { + assert(_parregs.size() == 0 || _parregs.size() >= (_cc->getResultCount() + _cc->getParamCount())); + assert(n < _cc->getResultCount()); + if (_parregs.size() == 0) + _prepareArgumentAndResultRegisterSpace(); + jitcs::VirtualRegister* &cell = _parregs[n]; + if (cell == nullptr) { + cell = createRegister(rc)._ptr; + } + assert(cell->regclass == rc); + return cell; +} +jitcs::Ref jitcs::FunctionImpl::createRegister(RegClassId rc, int logSz) { + // TODO: allocate registers blockwise... + VirtualRegister* r = _allocator->allocTyped(); + r->setupDynamic(*_mi, _vregs.size(), rc, logSz); + _vregs.push_back(r); + return r; +} /* void evm::Function::check() { @@ -135,17 +178,6 @@ evm::core::KillInsPtr evm::Function::createKillIns(BBlock* bb, u32 cnt) { } */ /* -evm::VReg * evm::Function::createVReg(RegClassId regclass, int sz) { -// assert(_allocator.isAligned(16)); - VReg* v = (VReg*)_allocator.alloc(RoundUpToP2<16>(sizeof(VReg))); - v->setupDynamic(_vregs.size(), regclass, 0, sz); - _vregs.push_back(v); - v->spillplacement.unplace(); - v->memref.clear(); - return v; -} -*/ -/* void evm::Function::allocateVRegMemRefs() { // assert(_allocator.isAligned(16)); u8* ptr = _allocator.alloc(MemPtr::SIZE * _vregs.size()); diff --git a/src/src/machine.cpp b/src/src/machine.cpp index e0f368f..f3902a3 100644 --- a/src/src/machine.cpp +++ b/src/src/machine.cpp @@ -1,4 +1,6 @@ #include "jitcs_machine.h" +#include "jitcs_function.h" +#include "jitcs_int_function_impl.h" jitcs::IMachineInfo::IMachineInfo(const CPUInfo& c) : cpu(c) { @@ -9,5 +11,9 @@ void jitcs::IMachineInfo::_release() { delete this; } -//std::unique_ptr -// createFnc(RefCounter, std::shared_ptr); +std::unique_ptr jitcs::IMachineInfo::createFnc + (RefCounter alloc, + std::shared_ptr cc) { + jitcs::FunctionImpl* f = new FunctionImpl(alloc, cc); + return std::unique_ptr(reinterpret_cast(f)); +} diff --git a/src/src/virtualregister.cpp b/src/src/virtualregister.cpp index 54ebc42..a958d16 100644 --- a/src/src/virtualregister.cpp +++ b/src/src/virtualregister.cpp @@ -1,6 +1,10 @@ #include "jitcs_int_virtualregister.h" #include "jitcs_machine.h" +namespace jitcs { + RegClassId GetRegClass(const VirtualRegister* r); +} + void jitcs::VirtualRegister::setupDynamic(IMachineInfo& mi, size_t vregno, RegClassId rc, u8 logSz_) { id = static_cast(R_HardwareLimit + vregno); res = static_cast(mi.getResCount() + vregno); @@ -8,3 +12,7 @@ void jitcs::VirtualRegister::setupDynamic(IMachineInfo& mi, size_t vregno, RegCl resclass = mi.getResClassOfRegClass(rc); logSz = logSz_ ? logSz_ : mi.getLogSizeOfRegClass(rc); } + +jitcs::RegClassId jitcs::GetRegClass(const VirtualRegister* r) { + return r ? r->regclass : RCL_None; +} diff --git a/src/x86/jitcs_int_x86_xx_regs.lh b/src/x86/jitcs_int_x86_xx_regs.lh index 6cc38e9..273c099 100644 --- a/src/x86/jitcs_int_x86_xx_regs.lh +++ b/src/x86/jitcs_int_x86_xx_regs.lh @@ -148,7 +148,7 @@ template<> struct ResClassInfoCT { template <> struct RegInfoCT { static const ResId RES_Id = static_cast(%(vv)); static const ResClassId RESCL_Id = RESCL_%(regc2resc[v.class]); - static const RegClassId RC_Id = RC_%(v.refclass or "Count"); + static const RegClassId RCL_Id = RCL_%(v.refclass or "Count"); static const uint VR_Idx = %(v2nn[v.name]["x"..N]); typedef RegLookup<_fixedRegister%(v2nn[v.name]["x"..N]), RSC_%(v.class)> RegAccessorType; }; @@ -167,7 +167,7 @@ template <> struct ResInfoCT<%(k-1)> { /*| local f,t = cl.dontalloc:match("^(%d+)%-(%d+)$") /*| if f and t then da = 2 ^ (t+1) - 2 ^ f end /*| end -template <> struct RegClassInfoCT { +template <> struct RegClassInfoCT { static const ResClassId RESCL_Id = RESCL_%(regc2resc[cl.classes[1]]); static const u16 MASK_DontAlloc = %(da); static const u8 SIZE = %(cl.defsz); @@ -183,9 +183,9 @@ template <> struct RegClassInfoCT { /*| end extern const u8 ArrayReg2RegClass[%(maxid-minid+1)]; extern const u8 ArrayReg2Res[%(maxid-minid+1)]; -extern const u8 ArrayRegClass2ResClass[RC_Count]; -extern const u8 ArrayRegClass2LogSize[RC_Count]; -extern const u16 ArrayRegClass2DontAlloc[RC_Count]; +extern const u8 ArrayRegClass2ResClass[RCL_Count]; +extern const u8 ArrayRegClass2LogSize[RCL_Count]; +extern const u16 ArrayRegClass2DontAlloc[RCL_Count]; extern const u8 ArrayRes2ResClass[RES_Count]; extern const u8 ArrayResClass2ResClassIndex[RESCL_Count]; extern const u8 ArrayResClass2ResClassSize[RESCL_Count]; @@ -199,18 +199,18 @@ static inline ResId GetResOfReg(RegId r) { return static_cast(ArrayReg2Res[r-%(minid)]); } static inline ResClassId GetResClassOfRegClass(RegClassId rc) { - assert(rc < RC_Count); + assert(rc < RCL_Count); return static_cast(ArrayRegClass2ResClass[rc]); } static inline ResClassId GetResClassOfReg(RegId r) { return GetResClassOfRegClass(GetRegClassOfReg(r)); } static inline u8 GetLogSizeOfRegClass(RegClassId rc) { - assert(rc < RC_Count); + assert(rc < RCL_Count); return ArrayRegClass2LogSize[rc]; } static inline u16 GetDontAllocOfRegClass(RegClassId rc) { - assert(rc < RC_Count); + assert(rc < RCL_Count); return ArrayRegClass2DontAlloc[rc]; } static inline ResClassId GetResClassOfRes(ResId res) { diff --git a/src/x86/src/x86_xx_insinfo.lcpp b/src/x86/src/x86_xx_insinfo.lcpp new file mode 100644 index 0000000..3dad212 --- /dev/null +++ b/src/x86/src/x86_xx_insinfo.lcpp @@ -0,0 +1,143 @@ +#/bin/emblua LUAPREFIX=/*| +/*| --VARDELIM=% +/*| --CMTDELIM=// +/*| --XDUMPSCRIPT=true +/*| --*/ +/*| local N = $$$ +/*| function pred_ipairs(t, pred) +/*| return function(t,k) +/*| local v +/*| repeat +/*| k = k + 1 +/*| v = t[k] +/*| until not v or pred(k, v) +/*| return v and k, v +/*| end, t, 0 +/*| end +/*| function isa(v) return not v[N==32 and "x64" or "x32only"] end +/*| function isaN(k,v) return not v[N==32 and "x64" or "x32"] end +#include "jitcs_x86_%(N)_cons.h" +#include "jitcs_x86_%(N)_machine.h" + +/*| local data= runfile("../../data/x86_inslist.dat") +/*| local function hex2(n) return string.format("0x%02x", n) end +/*| --*/ + +/*| cfclasses, cfclasslu = {}, {} +/*| submasks, submasklu, submasklist = {}, {}, {} +/*| for k,op in pred_ipairs(data.ops, function(k,op) return isa(op.opclass.isa) end) do +/*| local usesig, uselist = "", {} +/*| -- gather uses +/*| for k,v in ipairs(op.opclass.layout) do +/*| if (v[1]=="BBId") then +/*| usesig = usesig .. " BB"..k +/*| uselist[#uselist+1] = k +/*| end +/*| end +/*| local tp = nil +/*| for k,v in ipairs(op.opclass.flags) do +/*| if v == "cf_jmp" then usesig = usesig .. " JMP"; tp = "jmp" end +/*| if v == "cf_ret" then usesig = usesig .. " RET"; tp = "ret" end +/*| if v == "cf_fallthru" then usesig = usesig .. " FTHRU"; tp = tp or "jmp" end +/*| end +/*| op.opclass.cfsig = usesig +/*| if usesig ~= "" then +/*| end +/*| if usesig ~= "" and not cfclasslu[usesig] then +/*| local ud = {sig = usesig, list = uselist, tp = tp, ix = #cfclasses+1} +/*| cfclasses[#cfclasses+1] = ud +/*| cfclasslu[usesig] = ud +/*| end +/*| local t = submasks[op.opclass.id] +/*| if not t then t = {}; submasks[op.opclass.id] = t; op.opclass.submasktable = t end +/*| if op.sub and (op.sub < 0 or op.sub > 31) then +# ERROR in %(op.name) of class %(op.opclass.id): sub out of bounds +/*| end +/*| if t[op.sub or 0] and not string.sub(op.name, 1, 5) == "TEST_" then +# ERROR in %(op.name) of class %(op.opclass.id): sub entry twice encountered +/*| end +/*| t[op.sub or 0] = true +/*| submasks[op.opclass.id] = t +/*| end +/*| for k,v in pairs(submasks) do +/*| local sum, cnt = 0, 0 +/*| for k,v in pairs(v) do if type(k) == "number" then sum = sum + math.pow(2,k); cnt = cnt + 1 end end +/*| v.sum = sum +/*| v.cnt = cnt +/*| if not submasklu[sum] then submasklu[sum] = true; submasklist[#submasklist + 1] = sum end +/*| end +/*| table.sort(submasklist) +/*| local submask_inverse = {} +/*| for k,v in ipairs(submasklist) do submask_inverse[v] = k end +/*| for k,v in pairs(submasks) do v.sumindex = submask_inverse[v.sum] end + +#define COMBINE(A,B,C) (((A) << 12) | ((B) << 8) | (C)) +const jitcs::u16 jitcs::x86_%(N)::ArrayInsClassInfo + [jitcs::x86_%(N)::IC_Count - jitcs::x86_%(N)::IC_Invalid - 1] = { +/*| for k,cl in pred_ipairs(data.opclasses, function(k,cl) return isa(cl.isa) end) do +/*| local cf = cl.cfsig == "" and 0 or cfclasslu[cl.cfsig].ix or 0 +/*| local msk = cl.submasktable.sumindex - 1 +/*| local cnt = cl.submasktable.cnt + COMBINE(jitcs::x86_%(N)::InsClassSizeCT::Value, %(cf), %(msk)), // %(cnt) members +/*| end --*/ +}; +#undef COMBINE +static const jitcs::u32 _x86_%(N)_validmask[%(#submasklist)] = { +/*| for k,v in ipairs(submasklist) do + 0x%(string.format("%08x", v)), +/*| end --*/ +}; + +// +size_t jitcs::X86_%(N)MachineInfo::getInsIdInfo(InsId id) const { + jitcs::x86_%(N)::InsClassId cl = static_cast(id >> jitcs::x86_%(N)::IC_SubBits); + if (cl > jitcs::x86_%(N)::IC_Invalid && cl < jitcs::x86_%(N)::IC_Count) { + u16 v1 = jitcs::x86_%(N)::ArrayInsClassInfo[cl - jitcs::x86_%(N)::IC_Invalid - 1]; + u32 mask = _x86_%(N)_validmask[v1 & 0xff]; + if ((mask & (1 << (id & 0x1f))) == 0) + return 0; + return ((v1 >> 12) << 2) + 1 + ((v1 & 0xf00) != 0 ? 2 : 0); + } + return 0; +} + +#if 0 +bool evm::x86::IsCtrlFlowIns(InsPtr ip) { + teInsId id = (teInsId)ip.getInsId().id; + if ((id >> C_SubBits) > x86::C_Invalid && (id >> C_SubBits) < x86::C_Count) { + return _aX86CtrlFlowClass[(id >> C_SubBits) - x86::C_Invalid - 1] != 0; + } + return evm::core::IsCtrlFlowIns(ip); +} +bool evm::x86::IsCtrlFlowRetIns(InsPtr ip) { + teInsId id = (teInsId)ip.getInsId().id; + if ((id >> C_SubBits) > x86::C_Invalid && (id >> C_SubBits) < x86::C_Count) { + switch (_aX86CtrlFlowClass[(id >> C_SubBits) - x86::C_Invalid - 1]) { + default: + return false; +/*| for _,v in ipairs(cfclasses) do + case %(v.ix): + return %(v.tp == "ret" and "true" or "false"); +/*| end + } + } + return evm::core::IsCtrlFlowRetIns(ip); +} +void evm::x86::UpdateCtrlFlow(InsPtr ip, BBlock* src, Function& b) { + teInsId id = (teInsId)ip.getInsId().id; + if ((id >> C_SubBits) > x86::C_Invalid && (id >> C_SubBits) < x86::C_Count) { + switch (_aX86CtrlFlowClass[(id >> C_SubBits) - x86::C_Invalid - 1]) { + default: + break; +/*| for _,v in ipairs(cfclasses) do + case %(v.ix): +/*| for k,w in ipairs(v.list) do + b.addCtrlFlow(src, BBId::Make(ip.getOp(%w))); +/*| end + break; +/*| end + } + } + return evm::core::UpdateCtrlFlow(ip, src, b); +} +#endif diff --git a/src/x86/src/x86_xx_machine.lcpp b/src/x86/src/x86_xx_machine.lcpp index 2c204ef..8864f94 100644 --- a/src/x86/src/x86_xx_machine.lcpp +++ b/src/x86/src/x86_xx_machine.lcpp @@ -44,7 +44,7 @@ jitcs::ResClassId jitcs::X86_%(N)MachineInfo::getResClassOfReg(RegId r) const { } // jitcs::RegClassId jitcs::X86_%(N)MachineInfo::getRegClassCount() const { - return jitcs::x86_%(N)::RC_Count; + return jitcs::x86_%(N)::RCL_Count; } jitcs::ResClassId jitcs::X86_%(N)MachineInfo::getResClassOfRegClass(RegClassId rc) const { return jitcs::x86_%(N)::GetResClassOfRegClass(rc); diff --git a/src/x86/src/x86_xx_regs.lcpp b/src/x86/src/x86_xx_regs.lcpp index 5299306..700cd08 100644 --- a/src/x86/src/x86_xx_regs.lcpp +++ b/src/x86/src/x86_xx_regs.lcpp @@ -32,7 +32,7 @@ const jitcs::u8 jitcs::x86_%(N)::ArrayReg2RegClass[%(maxid-minid+1)] = { /*| for id = minid, maxid do /*| if id2r[id] then - jitcs::x86_%(N)::RegInfoCT::RC_Id, + jitcs::x86_%(N)::RegInfoCT::RCL_Id, /*| else 0, /*| end @@ -69,21 +69,21 @@ const jitcs::u8 jitcs::x86_%(N)::ArrayReg2Res[%(maxid-minid+1)] = { /*| --*/ -const jitcs::u8 jitcs::x86_%(N)::ArrayRegClass2ResClass[jitcs::x86_%(N)::RC_Count] = { +const jitcs::u8 jitcs::x86_%(N)::ArrayRegClass2ResClass[jitcs::x86_%(N)::RCL_Count] = { /*| for l,cl in pred_ipairs(data.refclasses,isaN) do - jitcs::x86_%(N)::RegClassInfoCT::RESCL_Id, + jitcs::x86_%(N)::RegClassInfoCT::RESCL_Id, /*| end /*| --*/ }; -const jitcs::u8 jitcs::x86_%(N)::ArrayRegClass2LogSize[jitcs::x86_%(N)::RC_Count] = { +const jitcs::u8 jitcs::x86_%(N)::ArrayRegClass2LogSize[jitcs::x86_%(N)::RCL_Count] = { /*| for l,cl in pred_ipairs(data.refclasses,isaN) do - jitcs::x86_%(N)::RegClassInfoCT::LOGSIZE, + jitcs::x86_%(N)::RegClassInfoCT::LOGSIZE, /*| end /*| --*/ }; -const jitcs::u16 jitcs::x86_%(N)::ArrayRegClass2DontAlloc[jitcs::x86_%(N)::RC_Count] = { +const jitcs::u16 jitcs::x86_%(N)::ArrayRegClass2DontAlloc[jitcs::x86_%(N)::RCL_Count] = { /*| for l,cl in pred_ipairs(data.refclasses,isaN) do - jitcs::x86_%(N)::RegClassInfoCT::MASK_DontAlloc, + jitcs::x86_%(N)::RegClassInfoCT::MASK_DontAlloc, /*| end /*| --*/ }; @@ -125,10 +125,10 @@ const jitcs::u8 jitcs::x86_%(N)::ArrayResClass2ResClassSize[jitcs::x86_%(N)::RES }; jitcs::RegId jitcs::x86_%(N)::GetRegIdForRes(RegClassId rc, ResId res) { - assert(res < RES_Count && rc < RC_Count); + assert(res < RES_Count && rc < RCL_Count); switch (rc) { /*| for l,cl in pred_ipairs(data.refclasses, isaN) do - case RC_%(cl.name): { + case RCL_%(cl.name): { /*| local rescl = regc2resc[cl.classes[1]] typedef jitcs::x86_%(N)::ResClassInfoCT ResClass; assert(uint(res) >= ResClass::RES_Idx @@ -195,7 +195,7 @@ const jitcs::VirtualRegister jitcs::x86_%(N)::_fixedRegister%(k - 1) (jitcs::VirtualRegister::VR_Static, static_cast(jitcs::x86_%(N)::R_%(v)), jitcs::x86_%(N)::RegInfoCT::RES_Id, - jitcs::x86_%(N)::RegInfoCT::RC_Id, + jitcs::x86_%(N)::RegInfoCT::RCL_Id, jitcs::x86_%(N)::RegInfoCT::RESCL_Id, - jitcs::x86_%(N)::RegClassInfoCT::RC_Id>::LOGSIZE); + jitcs::x86_%(N)::RegClassInfoCT::RCL_Id>::LOGSIZE); /*| end --*/ diff --git a/tests/test_simplefunction.cpp b/tests/test_simplefunction.cpp new file mode 100644 index 0000000..db1a1c6 --- /dev/null +++ b/tests/test_simplefunction.cpp @@ -0,0 +1,78 @@ +#include "jitcs.h" +#include "unittest.h" +#include "jitcs_instructionstream.h" + +#include + +using namespace jitcs; + +static void test(UnitTest& t) { + typedef int (__cdecl *FT0_c)(int, int); + RefCounter mi = host::GetMachineInfo(); + RefCounter alloc(new TempAllocator); + { + std::unique_ptr fn = mi->createFnc(alloc); + InstructionStreamBuffer<256> ibuf; + Ref param0 = fn->getArgumentRegister(0, host::RCL_GR); + Ref param1 = fn->getArgumentRegister(1, host::RCL_GR); + Ref result0 = fn->getResultRegister(0, host::RCL_GR); + Ref bb1 = fn->getStartBlock(); + Ref bb2 = fn->createBasicBlock(); + Ref bb3 = fn->createBasicBlock(); + ibuf.start(bb1); + host::CMP_RR(ibuf, param0, param1); + host::JGE_BB_FT(ibuf, bb2, bb3); + ibuf.end(); + + ibuf.start(bb2); + host::MOV_RR(ibuf, result0, param0); + host::RET(ibuf); + ibuf.end(); + + ibuf.start(bb3); + host::MOV_RR(ibuf, result0, param1); + host::RET(ibuf); + ibuf.end(); + + { + Enumerator enumbb = fn->enumerateBasicBlocks(); + size_t c = 0, c1 = 0, c2 = 0, c3 = 0; + while (!enumbb.empty()) { + const BasicBlock& bb = enumbb.front(); + ++c; + if (&bb == bb1._ptr) ++c1; + if (&bb == bb2._ptr) ++c2; + if (&bb == bb3._ptr) ++c3; + } + t.check("Build/Enumerate basic blocks", c1 == 1 && c2 == 1 && c3 == 1 && c == 3); + } + { + Enumerator enumins = bb1->instructions(); + bool ok = true; + ok = !enumins.empty(); + if (ok) { + const Instruction& ins = enumins.front(); + ok = ok && (ins.getInsId() == host::I_CMP_RR); + } + t.check("Build/Enumerate instructions on BB1/1", ok); + ok = ok && !enumins.empty(); + if (ok) { + const Instruction& ins = enumins.front(); + ok = ok && (ins.getInsId() == host::I_JGE_BB_FT); + } + t.check("Build/Enumerate instructions on BB1/2", ok); + ok = ok && enumins.empty(); + t.check("Build/Enumerate instructions on BB1/3", ok); + } + { + Enumerator predbb = bb1->predecessors(); + Enumerator succbb = bb1->successors(); + t.check("Build/Pred+succ are empty before CFG fix", predbb.empty() && succbb.empty()); + } + t.check("Fixing CFG not implemented", false); + t.check("Generating code not implemented", false); + t.check("Running function not implemented", false); + } +} + +static UnitTestRun _("SimpleFunction", test); diff --git a/tools/x86_inslist2data.lua b/tools/x86_inslist2data.lua index 4f3345d..3120287 100644 --- a/tools/x86_inslist2data.lua +++ b/tools/x86_inslist2data.lua @@ -261,6 +261,7 @@ local _prefset= { ["66"] = {}, ["f2"] = {}, ["f3"] = {}, + ["66f2"] = {}, -- only for crc32_16 } local function _parsePref(op, data) _opassert(not op.pref, op, "double prefix declaration") @@ -662,6 +663,7 @@ local function parseLine(name, defs) if not op.rex then op.rex = {mode = "rr", reg = "0", rm = "0", r64 = "0"} end if not op.extopcode then op.extopcode = "" end if not op.code then op.code = {} end + if op.pref == "66f2" then _assert(not op.rex.vex and not op.rex.evex) end --print(1, dump(op)) _checkOp(op) _createLayout(op) -- 2.11.4.GIT