From 3b20d3831cd63acbd9fb6b4c0104af4ef6baced9 Mon Sep 17 00:00:00 2001 From: huitailangzju <804544223@qq.com> Date: Tue, 20 Dec 2022 17:18:15 +0800 Subject: [PATCH] [Update] Update to v0.4.0 --- ...upport-for-new-insertion-points-and-.patch | 79 - 0002-Pin-gcc-client-Support-LoopOp.patch | 744 ---------- ...upport-build-CFG-CallOp-AssignOp-Con.patch | 1289 ----------------- ...c-client-Support-Plugin-Pointer-type.patch | 184 --- pin-gcc-client-0.3.0.tar.gz | Bin 33917 -> 0 bytes pin-gcc-client-0.4.0.tar.gz | Bin 0 -> 52554 bytes pin-gcc-client.spec | 20 +- 7 files changed, 8 insertions(+), 2308 deletions(-) delete mode 100644 0001-Pin-gcc-client-Support-for-new-insertion-points-and-.patch delete mode 100644 0002-Pin-gcc-client-Support-LoopOp.patch delete mode 100644 0003-Pin-gcc-client-Support-build-CFG-CallOp-AssignOp-Con.patch delete mode 100644 0004-Pin-gcc-client-Support-Plugin-Pointer-type.patch delete mode 100644 pin-gcc-client-0.3.0.tar.gz create mode 100644 pin-gcc-client-0.4.0.tar.gz diff --git a/0001-Pin-gcc-client-Support-for-new-insertion-points-and-.patch b/0001-Pin-gcc-client-Support-for-new-insertion-points-and-.patch deleted file mode 100644 index 912aecc..0000000 --- a/0001-Pin-gcc-client-Support-for-new-insertion-points-and-.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 1b9a024e5195a6860b7e6a896e0d7afa9794c277 Mon Sep 17 00:00:00 2001 -From: dingguangya -Date: Wed, 7 Dec 2022 21:49:19 +0800 -Subject: [PATCH 1/4] [Pin-gcc-client] Support for new insertion points and new - Pass It supports the phiopt insertion point and provides a simple - arraywiden pass interface. - ---- - include/PluginClient/PluginClient.h | 1 + - lib/IRTrans/IRTransPlugin.cpp | 25 +++++++++++++++++++++++++ - 2 files changed, 26 insertions(+) - -diff --git a/include/PluginClient/PluginClient.h b/include/PluginClient/PluginClient.h -index e8adcb2..155705d 100644 ---- a/include/PluginClient/PluginClient.h -+++ b/include/PluginClient/PluginClient.h -@@ -79,6 +79,7 @@ typedef enum { - // 参考点名称 - enum RefPassName { - PASS_CFG, -+ PASS_PHIOPT, - PASS_SSA, - PASS_LOOP, - }; -diff --git a/lib/IRTrans/IRTransPlugin.cpp b/lib/IRTrans/IRTransPlugin.cpp -index ccde9b5..8e5af8c 100644 ---- a/lib/IRTrans/IRTransPlugin.cpp -+++ b/lib/IRTrans/IRTransPlugin.cpp -@@ -127,8 +127,28 @@ void ManagerSetupCallback(void) - std::shared_ptr client = PluginClient::GetInstance(); - vector userFuncs = client->GetFuncNameByInject(inject); - for (auto &userFunc : userFuncs) { -+ if (client->GetUserFuncState() == STATE_TIMEOUT) { -+ break; -+ } - string value = std::to_string(inject) + ":" + userFunc; - client->ReceiveSendMsg(key, value); -+ while (1) { -+ UserFuncStateEnum state = client->GetUserFuncState(); -+ /* server获取到client对应函数的执行结果后,向client回复已执行完,跳出循环执行下一个函数 */ -+ if (state == STATE_END) { -+ client->SetUserFuncState(STATE_WAIT_BEGIN); -+ break; -+ } else if (state == STATE_TIMEOUT) { -+ break; -+ } else if (state == STATE_BEGIN) { -+ string funcName = client->GetPluginAPIName(); -+ string param = client->GetPluginAPIParam(); -+ if (funcName != "") { -+ client->SetUserFuncState(STATE_WAIT_IR); -+ client->IRTransBegin(funcName, param); -+ } -+ } -+ } - } - } - -@@ -182,6 +202,7 @@ public: - - static std::map g_refPassName { - {PASS_CFG, "cfg"}, -+ {PASS_PHIOPT, "phiopt"}, - {PASS_SSA, "ssa"}, - {PASS_LOOP, "loop"}, - }; -@@ -213,6 +234,10 @@ int RegisterPassManagerSetup(InjectPoint inject, const ManagerSetupData& setupDa - passData.type = GIMPLE_PASS; - passInfo.pass = new GimplePass(passData); - break; -+ case PASS_PHIOPT: -+ passData.type = GIMPLE_PASS; -+ passInfo.pass = new GimplePass(passData); -+ break; - case PASS_SSA: - passData.type = RTL_PASS; - passInfo.pass = new RltPass(passData); --- -2.27.0.windows.1 - diff --git a/0002-Pin-gcc-client-Support-LoopOp.patch b/0002-Pin-gcc-client-Support-LoopOp.patch deleted file mode 100644 index c11fec0..0000000 --- a/0002-Pin-gcc-client-Support-LoopOp.patch +++ /dev/null @@ -1,744 +0,0 @@ -From f5ca57ff4a1ee37da47949abea958ba595b895d2 Mon Sep 17 00:00:00 2001 -From: benniaobufeijiushiji -Date: Mon, 5 Dec 2022 17:02:18 +0800 -Subject: [PATCH 2/4] [Pin-gcc-client] Support LoopOp Add LoopOp for Plugin - Dialect - ---- - include/Dialect/PluginOps.td | 19 ++ - include/PluginAPI/BasicPluginOpsAPI.h | 12 + - include/PluginAPI/PluginClientAPI.h | 12 + - include/PluginClient/PluginClient.h | 9 + - include/Translate/GimpleToPluginOps.h | 13 +- - include/Translate/ToPluginOpsInterface.h | 12 + - lib/Dialect/PluginOps.cpp | 13 +- - lib/IRTrans/IRTransPlugin.cpp | 1 + - lib/PluginAPI/PluginClientAPI.cpp | 58 +++++ - lib/PluginClient/PluginClient.cpp | 267 ++++++++++++++++++++++- - lib/Translate/GimpleToPluginOps.cpp | 139 +++++++++++- - 11 files changed, 549 insertions(+), 6 deletions(-) - -diff --git a/include/Dialect/PluginOps.td b/include/Dialect/PluginOps.td -index 98f5cad..8264555 100644 ---- a/include/Dialect/PluginOps.td -+++ b/include/Dialect/PluginOps.td -@@ -56,4 +56,23 @@ def LocalDeclOp : Plugin_Op<"declaration", [NoSideEffect]> { - ]; - } - -+def LoopOp : Plugin_Op<"loop", [NoSideEffect]> { -+ let summary = "loop operation"; -+ let description = [{ -+ TODO. -+ }]; -+ let arguments = (ins OptionalAttr:$id, -+ OptionalAttr:$index, -+ OptionalAttr:$innerLoopId, -+ OptionalAttr:$outerLoopId, -+ OptionalAttr:$numBlock); -+ let regions = (region AnyRegion:$bodyRegion); -+ let builders = [ -+ OpBuilderDAG<(ins "uint64_t":$id, "uint32_t":$index, -+ "uint64_t":$innerLoopId, "uint64_t":$outerLoopId, -+ "uint32_t":$numBlock)> -+ ]; -+} -+ -+ - #endif // PLUGIN_OPS_TD -\ No newline at end of file -diff --git a/include/PluginAPI/BasicPluginOpsAPI.h b/include/PluginAPI/BasicPluginOpsAPI.h -index 24147e1..1037bf5 100644 ---- a/include/PluginAPI/BasicPluginOpsAPI.h -+++ b/include/PluginAPI/BasicPluginOpsAPI.h -@@ -43,6 +43,18 @@ public: - - virtual vector GetAllFunc() = 0; - virtual vector GetDecls(uint64_t funcID) = 0; -+ virtual vector GetLoopsFromFunc(uint64_t) = 0; -+ virtual LoopOp GetLoopById(uint64_t) = 0; -+ virtual bool IsBlockInside(uint64_t, uint64_t) = 0; -+ virtual vector GetBlocksInLoop(uint64_t) = 0; -+ virtual void AddLoop(uint64_t, uint64_t, uint64_t) = 0; -+ virtual uint64_t AllocateNewLoop(void) = 0; -+ virtual void DeleteLoop(uint64_t) = 0; -+ virtual uint64_t GetHeader(uint64_t) = 0; -+ virtual uint64_t GetLatch(uint64_t) = 0; -+ virtual vector > GetLoopExits(uint64_t) = 0; -+ virtual std::pair GetLoopSingleExit(uint64_t) = 0; -+ virtual LoopOp GetBlockLoopFather(uint64_t) = 0; - }; // class BasicPluginOpsAPI - } // namespace PluginAPI - -diff --git a/include/PluginAPI/PluginClientAPI.h b/include/PluginAPI/PluginClientAPI.h -index b4f1ef3..42d56ee 100644 ---- a/include/PluginAPI/PluginClientAPI.h -+++ b/include/PluginAPI/PluginClientAPI.h -@@ -35,6 +35,18 @@ public: - - vector GetAllFunc() override; - vector GetDecls(uint64_t funcID) override; -+ vector GetLoopsFromFunc(uint64_t) override; -+ LoopOp GetLoopById(uint64_t) override; -+ bool IsBlockInside(uint64_t, uint64_t) override; -+ vector GetBlocksInLoop(uint64_t) override; -+ void AddLoop(uint64_t, uint64_t, uint64_t) override; -+ uint64_t AllocateNewLoop(void) override; -+ void DeleteLoop(uint64_t) override; -+ uint64_t GetHeader(uint64_t) override; -+ uint64_t GetLatch(uint64_t) override; -+ vector > GetLoopExits(uint64_t) override; -+ std::pair GetLoopSingleExit(uint64_t) override; -+ LoopOp GetBlockLoopFather(uint64_t) override; - - private: - PluginIR::GimpleToPluginOps gimpleConversion; -diff --git a/include/PluginClient/PluginClient.h b/include/PluginClient/PluginClient.h -index 155705d..3e48c44 100644 ---- a/include/PluginClient/PluginClient.h -+++ b/include/PluginClient/PluginClient.h -@@ -43,6 +43,7 @@ using std::string; - using std::endl; - using std::vector; - using std::map; -+using std::pair; - - using plugin::PluginService; - using grpc::Channel; -@@ -107,6 +108,14 @@ public: - static std::shared_ptr GetInstance(void); - void OpJsonSerialize(vector& data, string& out); - void LocalDeclsJsonSerialize(vector& decls, string& out); -+ void LoopOpsJsonSerialize(vector& loops, string& out); -+ void LoopOpJsonSerialize(mlir::Plugin::LoopOp& loop, string& out); -+ void BoolResultJsonSerialize(bool, string&); -+ void BlockJsonSerialize(uint64_t, string&); -+ void BlocksJsonSerialize(vector&, string&); -+ void EdgesJsonSerialize(vector >&, string&); -+ void EdgeJsonSerialize(pair&, string&); -+ void NopJsonSerialize(string&); - /* 将Type类型数据序列化 */ - void TypeJsonSerialize(PluginIR::PluginTypeBase& type, string& out); - /* 获取gcc插件数据并进行IR转换,将转换后的数据序列化返回给server。param:函数入参序列化后的数据 */ -diff --git a/include/Translate/GimpleToPluginOps.h b/include/Translate/GimpleToPluginOps.h -index 2acd4a5..3f4f96a 100644 ---- a/include/Translate/GimpleToPluginOps.h -+++ b/include/Translate/GimpleToPluginOps.h -@@ -44,7 +44,18 @@ public: - /* ToPluginInterface */ - vector GetAllFunction() override; - vector GetAllDecls(uint64_t) override; -- -+ vector GetAllLoops(uint64_t) override; -+ LoopOp GetLoop(uint64_t) override; -+ bool IsBlockInside(uint64_t, uint64_t) override; -+ vector GetBlocksInLoop(uint64_t) override; -+ uint64_t AllocateNewLoop(void) override; -+ void DeleteLoop(uint64_t) override; -+ void AddLoop (uint64_t, uint64_t, uint64_t) override; -+ uint64_t GetHeader(uint64_t) override; -+ uint64_t GetLatch(uint64_t) override; -+ vector > GetLoopExits(uint64_t) override; -+ std::pair GetLoopSingleExit(uint64_t) override; -+ LoopOp GetBlockLoopFather(uint64_t) override; - private: - mlir::OpBuilder builder; - TypeFromPluginIRTranslator typeTranslator; -diff --git a/include/Translate/ToPluginOpsInterface.h b/include/Translate/ToPluginOpsInterface.h -index 881eb7f..598c176 100644 ---- a/include/Translate/ToPluginOpsInterface.h -+++ b/include/Translate/ToPluginOpsInterface.h -@@ -37,6 +37,18 @@ public: - /* Operation. */ - virtual vector GetAllFunction() = 0; - virtual vector GetAllDecls(uint64_t) = 0; -+ virtual vector GetAllLoops(uint64_t) = 0; -+ virtual LoopOp GetLoop(uint64_t) = 0; -+ virtual bool IsBlockInside(uint64_t, uint64_t) = 0; -+ virtual vector GetBlocksInLoop(uint64_t) = 0; -+ virtual uint64_t AllocateNewLoop(void) = 0; -+ virtual void DeleteLoop(uint64_t) = 0; -+ virtual void AddLoop (uint64_t, uint64_t, uint64_t) = 0; -+ virtual uint64_t GetHeader(uint64_t) = 0; -+ virtual uint64_t GetLatch(uint64_t) = 0; -+ virtual vector > GetLoopExits(uint64_t) = 0; -+ virtual std::pair GetLoopSingleExit(uint64_t) = 0; -+ virtual LoopOp GetBlockLoopFather(uint64_t) = 0; - }; - } // namespace PluginIR - -diff --git a/lib/Dialect/PluginOps.cpp b/lib/Dialect/PluginOps.cpp -index 4caa890..adf7ca6 100644 ---- a/lib/Dialect/PluginOps.cpp -+++ b/lib/Dialect/PluginOps.cpp -@@ -35,7 +35,7 @@ using namespace mlir::Plugin; - void FunctionOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, - uint64_t id, StringRef funcName, bool declaredInline) { - FunctionOp::build(builder, state, -- builder.getI64IntegerAttr(id), -+ builder.getI64IntegerAttr(id), - builder.getStringAttr(funcName), - builder.getBoolAttr(declaredInline)); - } -@@ -50,6 +50,17 @@ void LocalDeclOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, - builder.getI64IntegerAttr(typeWidth)); - } - -+void LoopOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, -+ uint64_t id, uint32_t index, uint64_t innerLoopId, -+ uint64_t outerLoopId, uint32_t numBlock) { -+ LoopOp::build(builder, state, -+ builder.getI64IntegerAttr(id), -+ builder.getI32IntegerAttr(index), -+ builder.getI64IntegerAttr(innerLoopId), -+ builder.getI64IntegerAttr(outerLoopId), -+ builder.getI32IntegerAttr(numBlock)); -+} -+ - //===----------------------------------------------------------------------===// - // TableGen'd op method definitions - //===----------------------------------------------------------------------===// -diff --git a/lib/IRTrans/IRTransPlugin.cpp b/lib/IRTrans/IRTransPlugin.cpp -index 8e5af8c..b1cc616 100644 ---- a/lib/IRTrans/IRTransPlugin.cpp -+++ b/lib/IRTrans/IRTransPlugin.cpp -@@ -31,6 +31,7 @@ - #include "context.h" - #include "tree-pass.h" - #include "tree.h" -+#include "tree-cfg.h" - - using namespace PinClient; - -diff --git a/lib/PluginAPI/PluginClientAPI.cpp b/lib/PluginAPI/PluginClientAPI.cpp -index 028023d..d268c1e 100644 ---- a/lib/PluginAPI/PluginClientAPI.cpp -+++ b/lib/PluginAPI/PluginClientAPI.cpp -@@ -29,4 +29,62 @@ vector PluginClientAPI::GetDecls(uint64_t funcID) - return gimpleConversion.GetAllDecls(funcID); - } - -+vector PluginClientAPI::GetLoopsFromFunc(uint64_t funcID) -+{ -+ return gimpleConversion.GetAllLoops(funcID); -+} -+ -+LoopOp PluginClientAPI::GetLoopById(uint64_t loopID) -+{ -+ return gimpleConversion.GetLoop(loopID); -+} -+ -+bool PluginClientAPI::IsBlockInside(uint64_t loopID, uint64_t blockID) -+{ -+ return gimpleConversion.IsBlockInside(loopID, blockID); -+} -+ -+vector PluginClientAPI::GetBlocksInLoop(uint64_t loopID) -+{ -+ return gimpleConversion.GetBlocksInLoop(loopID); -+} -+ -+void PluginClientAPI::AddLoop (uint64_t loop, uint64_t outer, uint64_t funcId) -+{ -+ gimpleConversion.AddLoop(loop, outer, funcId); -+} -+ -+uint64_t PluginClientAPI::AllocateNewLoop(void) -+{ -+ return gimpleConversion.AllocateNewLoop(); -+} -+void PluginClientAPI::DeleteLoop(uint64_t loopId) -+{ -+ gimpleConversion.DeleteLoop(loopId); -+} -+ -+uint64_t PluginClientAPI::GetHeader(uint64_t loopId) -+{ -+ return gimpleConversion.GetHeader(loopId); -+} -+ -+uint64_t PluginClientAPI::GetLatch(uint64_t loopId) -+{ -+ return gimpleConversion.GetLatch(loopId); -+} -+ -+vector > PluginClientAPI::GetLoopExits(uint64_t loopId) -+{ -+ return gimpleConversion.GetLoopExits(loopId); -+} -+std::pair PluginClientAPI::GetLoopSingleExit(uint64_t loopId) -+{ -+ return gimpleConversion.GetLoopSingleExit(loopId); -+} -+ -+LoopOp PluginClientAPI::GetBlockLoopFather(uint64_t blockId) -+{ -+ return gimpleConversion.GetBlockLoopFather(blockId); -+} -+ - } // namespace PluginAPI -\ No newline at end of file -diff --git a/lib/PluginClient/PluginClient.cpp b/lib/PluginClient/PluginClient.cpp -index 97dfadf..c57d36c 100644 ---- a/lib/PluginClient/PluginClient.cpp -+++ b/lib/PluginClient/PluginClient.cpp -@@ -122,7 +122,7 @@ void PluginClient::OpJsonSerialize(vector& data, string& out) - item["attributes"]["declaredInline"] = "1"; - else - item["attributes"]["declaredInline"] = "0"; -- item["attributes"]["funcName"] = d.funcNameAttr().getValue().data(); -+ item["attributes"]["funcName"] = d.funcNameAttr().getValue().str(); - operation = "operation" + std::to_string(i++); - root[operation] = item; - item.clear(); -@@ -150,6 +150,101 @@ void PluginClient::LocalDeclsJsonSerialize(vector& decls, string& o - out = root.toStyledString(); - } - -+void PluginClient::LoopOpsJsonSerialize(vector& loops, string& out) -+{ -+ Json::Value root; -+ Json::Value operationObj; -+ Json::Value item; -+ int i = 0; -+ string operation; -+ -+ for (auto&loop: loops) { -+ item["id"] = std::to_string(loop.idAttr().getInt()); -+ item["index"] = std::to_string(loop.indexAttr().getInt()); -+ item["attributes"]["innerLoopId"] = std::to_string(loop.innerLoopIdAttr().getInt()); -+ item["attributes"]["outerLoopId"] = std::to_string(loop.outerLoopIdAttr().getInt()); -+ item["attributes"]["numBlock"] = std::to_string(loop.numBlockAttr().getInt()); -+ operation = "operation" + std::to_string(i++); -+ root[operation] = item; -+ item.clear(); -+ } -+ out = root.toStyledString(); -+} -+ -+void PluginClient::LoopOpJsonSerialize(mlir::Plugin::LoopOp& loop, string& out) -+{ -+ Json::Value root; -+ root["id"] = std::to_string(loop.idAttr().getInt()); -+ root["index"] = std::to_string(loop.indexAttr().getInt()); -+ root["attributes"]["innerLoopId"] = std::to_string(loop.innerLoopIdAttr().getInt()); -+ root["attributes"]["outerLoopId"] = std::to_string(loop.outerLoopIdAttr().getInt()); -+ root["attributes"]["numBlock"] = std::to_string(loop.numBlockAttr().getInt()); -+ out = root.toStyledString(); -+} -+ -+void PluginClient::BlocksJsonSerialize(vector& blocks, string& out) -+{ -+ Json::Value root; -+ Json::Value item; -+ int i = 0; -+ string index; -+ -+ for(auto& block : blocks) { -+ item["id"] = std::to_string(block); -+ index = "block" + std::to_string(i++); -+ root[index] = item; -+ item.clear(); -+ } -+ out = root.toStyledString(); -+} -+ -+void PluginClient::BlockJsonSerialize(uint64_t block, string& out) -+{ -+ Json::Value root; -+ Json::Value item; -+ root["id"] = std::to_string(block); -+ out = root.toStyledString(); -+} -+ -+void PluginClient::EdgesJsonSerialize(vector >& edges, string& out) -+{ -+ Json::Value root; -+ Json::Value item; -+ int i = 0; -+ string index; -+ -+ for(auto& edge : edges) { -+ item["src"] = std::to_string(edge.first); -+ item["dest"] = std::to_string(edge.second); -+ index = "edge" + std::to_string(i++); -+ root[index] = item; -+ item.clear(); -+ } -+ out = root.toStyledString(); -+} -+ -+void PluginClient::EdgeJsonSerialize(pair& edge, string& out) -+{ -+ Json::Value root; -+ root["src"] = std::to_string(edge.first); -+ root["dest"] = std::to_string(edge.second); -+ out = root.toStyledString(); -+} -+ -+void PluginClient::BoolResultJsonSerialize(bool res, string& out) -+{ -+ Json::Value root; -+ root["result"] = std::to_string((int)res); -+ out = root.toStyledString(); -+} -+ -+// void类型的Json序列化 -+void PluginClient::NopJsonSerialize(string& out) -+{ -+ Json::Value root; -+ out = root.toStyledString(); -+} -+ - void PluginClient::IRTransBegin(const string& funcName, const string& param) - { - string result; -@@ -168,14 +263,180 @@ void PluginClient::IRTransBegin(const string& funcName, const string& param) - OpJsonSerialize(allFuncOps, result); - this->ReceiveSendMsg("FuncOpResult", result); - } else if (funcName == "GetLocalDecls") { -+ /// Json格式 -+ /// { -+ /// "funcId":"xxxx" -+ /// } - mlir::MLIRContext context; - context.getOrLoadDialect(); - PluginAPI::PluginClientAPI clientAPI(context); -- uint64_t funcID = atol(root[std::to_string(0)].asString().c_str()); -+ std::string funcIdKey = "funcId"; -+ uint64_t funcID = atol(root[funcIdKey].asString().c_str()); - vector decls = clientAPI.GetDecls(funcID); - LocalDeclsJsonSerialize(decls, result); - this->ReceiveSendMsg("LocalDeclOpResult", result); -- }else { -+ } else if (funcName == "GetLoopsFromFunc") { -+ /// Json格式 -+ /// { -+ /// "funcId":"xxxx" -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string funcIdKey = "funcId"; -+ uint64_t funcID = atol(root[funcIdKey].asString().c_str()); -+ vector irLoops = clientAPI.GetLoopsFromFunc(funcID); -+ LoopOpsJsonSerialize(irLoops, result); -+ this->ReceiveSendMsg("LoopOpsResult", result); -+ } else if (funcName == "GetLoopById") { -+ /// Json格式 -+ /// { -+ /// "loopId":"xxxx" -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string loopIdKey = "loopId"; -+ uint64_t loopId = atol(root[loopIdKey].asString().c_str()); -+ LoopOp irLoop = clientAPI.GetLoopById(loopId); -+ LoopOpJsonSerialize(irLoop, result); -+ this->ReceiveSendMsg("LoopOpResult", result); -+ } else if (funcName == "IsBlockInside") { -+ /// Json格式 -+ /// { -+ /// "loopId":"xxxx", -+ /// "blockId":"xxxx" -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string loopIdKey = "loopId"; -+ std::string blockIdKey = "blockId"; -+ uint64_t loopId = atol(root[loopIdKey].asString().c_str()); -+ uint64_t blockId = atol(root[blockIdKey].asString().c_str()); -+ bool res = clientAPI.IsBlockInside(loopId, blockId); -+ BoolResultJsonSerialize(res, result); -+ this->ReceiveSendMsg("BoolResult", result); -+ } else if (funcName == "AllocateNewLoop") { -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ uint64_t newLoopId = clientAPI.AllocateNewLoop(); -+ LoopOp newLoop = clientAPI.GetLoopById(newLoopId); -+ LoopOpJsonSerialize(newLoop, result); -+ this->ReceiveSendMsg("LoopOpResult", result); -+ } else if (funcName == "DeleteLoop") { -+ /// Json格式 -+ /// { -+ /// "loopId":"xxxx", -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string loopIdKey = "loopId"; -+ uint64_t loopId = atol(root[loopIdKey].asString().c_str()); -+ clientAPI.DeleteLoop(loopId); -+ NopJsonSerialize(result); -+ this->ReceiveSendMsg("VoidResult", result); -+ } else if (funcName == "AddLoop") { -+ /// Json格式 -+ /// { -+ /// "loopId":"xxxx", -+ /// "outerId":"xxxx" -+ /// "funcId":"xxxx" -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string loopIdKey = "loopId"; -+ std::string outerIdKey = "outerId"; -+ std::string funcIdKey = "funcId"; -+ uint64_t loopID = atol(root[loopIdKey].asString().c_str()); -+ uint64_t outerID = atol(root[outerIdKey].asString().c_str()); -+ uint64_t funcID = atol(root[funcIdKey].asString().c_str()); -+ clientAPI.AddLoop(loopID, outerID, funcID); -+ LoopOp irLoop = clientAPI.GetLoopById(loopID); -+ LoopOpJsonSerialize(irLoop, result); -+ this->ReceiveSendMsg("LoopOpResult", result); -+ } else if (funcName == "GetBlocksInLoop") { -+ /// Json格式 -+ /// { -+ /// "loopId":"xxxx", -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string loopIdKey = "loopId"; -+ uint64_t loopId = atol(root[loopIdKey].asString().c_str()); -+ vector blocks = clientAPI.GetBlocksInLoop(loopId); -+ BlocksJsonSerialize(blocks, result); -+ this->ReceiveSendMsg("BlockIdsResult", result); -+ } else if (funcName == "GetHeader") { -+ /// Json格式 -+ /// { -+ /// "loopId":"xxxx", -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string loopIdKey = "loopId"; -+ uint64_t loopId = atol(root[loopIdKey].asString().c_str()); -+ uint64_t blockId = clientAPI.GetHeader(loopId); -+ BlockJsonSerialize(blockId, result); -+ this->ReceiveSendMsg("BlockIdResult", result); -+ } else if (funcName == "GetLatch") { -+ /// Json格式 -+ /// { -+ /// "loopId":"xxxx", -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string loopIdKey = "loopId"; -+ uint64_t loopId = atol(root[loopIdKey].asString().c_str()); -+ uint64_t blockId = clientAPI.GetLatch(loopId); -+ BlockJsonSerialize(blockId, result); -+ this->ReceiveSendMsg("BlockIdResult", result); -+ } else if (funcName == "GetLoopExits") { -+ /// Json格式 -+ /// { -+ /// "loopId":"xxxx", -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string loopIdKey = "loopId"; -+ uint64_t loopId = atol(root[loopIdKey].asString().c_str()); -+ vector > edges = clientAPI.GetLoopExits(loopId); -+ EdgesJsonSerialize(edges, result); -+ this->ReceiveSendMsg("EdgesResult", result); -+ } else if (funcName == "GetLoopSingleExit") { -+ /// Json格式 -+ /// { -+ /// "loopId":"xxxx", -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string loopIdKey = "loopId"; -+ uint64_t loopId = atol(root[loopIdKey].asString().c_str()); -+ pair edge = clientAPI.GetLoopSingleExit(loopId); -+ EdgeJsonSerialize(edge, result); -+ this->ReceiveSendMsg("EdgeResult", result); -+ } else if (funcName == "GetBlockLoopFather") { -+ /// Json格式 -+ /// { -+ /// "blockId":"xxxx", -+ /// } -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ std::string blockIdKey = "blockId"; -+ uint64_t blockId = atol(root[blockIdKey].asString().c_str()); -+ LoopOp loopFather = clientAPI.GetBlockLoopFather(blockId); -+ LoopOpJsonSerialize(loopFather, result); -+ this->ReceiveSendMsg("LoopOpResult", result); -+ } else { - LOGW("function: %s not found!\n", funcName.c_str()); - } - -diff --git a/lib/Translate/GimpleToPluginOps.cpp b/lib/Translate/GimpleToPluginOps.cpp -index 2d021fe..273a214 100644 ---- a/lib/Translate/GimpleToPluginOps.cpp -+++ b/lib/Translate/GimpleToPluginOps.cpp -@@ -41,6 +41,8 @@ - #include "ssa.h" - #include "output.h" - #include "langhooks.h" -+#include "cfgloop.h" -+#include "tree-cfg.h" - - namespace PluginIR { - using namespace mlir::Plugin; -@@ -82,7 +84,7 @@ vector GimpleToPluginOps::GetAllDecls(uint64_t funcID) - const char* name = IDENTIFIER_POINTER(DECL_NAME (var)); - mlir::StringRef symName(name); - auto location = builder.getUnknownLoc(); -- PluginTypeBase declType = typeTranslator.translateType((intptr_t)TREE_TYPE(var)); -+ PluginTypeBase declType = typeTranslator.translateType((intptr_t)TREE_TYPE(var)); - int64_t typeID = typeTranslator.getPluginTypeId (declType); - uint64_t typeWidth = typeTranslator.getBitWidth (declType); - decl = builder.create(location, id, symName, typeID, typeWidth); -@@ -92,4 +94,139 @@ vector GimpleToPluginOps::GetAllDecls(uint64_t funcID) - return decls; - } - -+vector GimpleToPluginOps::GetAllLoops(uint64_t funcID) -+{ -+ function *fn = reinterpret_cast(funcID); -+ push_cfun(fn); -+ vector loops; -+ enum li_flags LI = LI_FROM_INNERMOST; -+ class loop *loop; -+ FOR_EACH_LOOP(loop, LI) { -+ uint64_t id = reinterpret_cast(reinterpret_cast(loop)); -+ LoopOp pluginLoop; -+ if (!id) { -+ continue; -+ } -+ auto location = builder.getUnknownLoc(); -+ uint32_t index = (uint32_t)loop->num; -+ uint64_t innerLoopId = reinterpret_cast(reinterpret_cast(loop->inner)); -+ uint64_t outerLoopId = reinterpret_cast(reinterpret_cast(loop_outer(loop))); -+ uint32_t numBlock = loop->num_nodes; -+ pluginLoop = builder.create(location, id, index, innerLoopId, outerLoopId, numBlock); -+ loops.push_back(pluginLoop); -+ } -+ pop_cfun(); -+ return loops; -+} -+ -+LoopOp GimpleToPluginOps::GetLoop(uint64_t loopID) -+{ -+ assert(loopID); -+ class loop *loop = reinterpret_cast(loopID); -+ uint64_t id = loopID; -+ LoopOp pluginLoop; -+ auto location = builder.getUnknownLoc(); -+ uint32_t index = (uint32_t)loop->num; -+ uint64_t innerLoopId = reinterpret_cast(reinterpret_cast(loop->inner)); -+ uint64_t outerLoopId = reinterpret_cast(reinterpret_cast(loop_outer(loop))); -+ uint32_t numBlock = loop->num_nodes; -+ pluginLoop = builder.create(location, id, index, innerLoopId, outerLoopId, numBlock); -+ return pluginLoop; -+} -+ -+bool GimpleToPluginOps::IsBlockInside(uint64_t loopID, uint64_t blockID) -+{ -+ assert(loopID && blockID); -+ class loop *loop = reinterpret_cast(loopID); -+ basic_block bb = reinterpret_cast(reinterpret_cast(blockID)); -+ return flow_bb_inside_loop_p(loop, bb); -+} -+ -+vector GimpleToPluginOps::GetBlocksInLoop(uint64_t loopID) -+{ -+ assert(loopID); -+ vector blocks; -+ class loop *loop = reinterpret_cast(loopID); -+ basic_block *bbs = get_loop_body_in_dom_order(loop); -+ for (unsigned i = 0; i < loop->num_nodes; i++) { -+ uint64_t blockId = reinterpret_cast(reinterpret_cast(bbs[i])); -+ blocks.push_back(blockId); -+ } -+ return blocks; -+} -+ -+uint64_t GimpleToPluginOps::AllocateNewLoop(void) -+{ -+ class loop *loop = alloc_loop(); -+ return reinterpret_cast(reinterpret_cast(loop)); -+} -+ -+void GimpleToPluginOps::DeleteLoop(uint64_t loopID) -+{ -+ class loop *loop = reinterpret_cast(reinterpret_cast(loopID)); -+ delete_loop(loop); -+} -+ -+void GimpleToPluginOps::AddLoop(uint64_t loopID, uint64_t outerID, uint64_t funcID) -+{ -+ class loop *loop = reinterpret_cast(loopID); -+ class loop *outer = reinterpret_cast(outerID); -+ function *fn = reinterpret_cast(funcID); -+ push_cfun(fn); -+ add_loop(loop, outer); -+ pop_cfun(); -+} -+ -+uint64_t GimpleToPluginOps::GetHeader(uint64_t loopID) -+{ -+ class loop *loop = reinterpret_cast(loopID); -+ basic_block header = loop->header; -+ return reinterpret_cast(reinterpret_cast(header)); -+} -+ -+uint64_t GimpleToPluginOps::GetLatch(uint64_t loopID) -+{ -+ class loop *loop = reinterpret_cast(loopID); -+ basic_block latch = loop->latch; -+ return reinterpret_cast(reinterpret_cast(latch)); -+} -+ -+vector > GimpleToPluginOps::GetLoopExits(uint64_t loopID) -+{ -+ class loop *loop = reinterpret_cast(loopID); -+ vec exit_edges = get_loop_exit_edges(loop); -+ edge e; -+ unsigned i = 0; -+ vector > res; -+ FOR_EACH_VEC_ELT(exit_edges, i, e) { -+ res.push_back(std::make_pair((uint64_t)e->src, (uint64_t)e->dest)); -+ } -+ return res; -+} -+ -+std::pair GimpleToPluginOps::GetLoopSingleExit(uint64_t loopID) -+{ -+ class loop *loop = reinterpret_cast(loopID); -+ edge e = single_exit(loop); -+ std::pair res; -+ res.first = e ? (uint64_t)e->src : 0; -+ res.second = e ? (uint64_t)e->dest : 0; -+ return res; -+} -+ -+LoopOp GimpleToPluginOps::GetBlockLoopFather(uint64_t blockID) -+{ -+ basic_block bb = reinterpret_cast(reinterpret_cast(blockID)); -+ class loop *loop = bb->loop_father; -+ LoopOp pluginLoop; -+ auto location = builder.getUnknownLoc(); -+ uint64_t id = reinterpret_cast(loop); -+ uint32_t index = (uint32_t)loop->num; -+ uint64_t innerLoopId = reinterpret_cast(reinterpret_cast(loop->inner)); -+ uint64_t outerLoopId = reinterpret_cast(reinterpret_cast(loop_outer(loop))); -+ uint32_t numBlock = loop->num_nodes; -+ pluginLoop = builder.create(location, id, index, innerLoopId, outerLoopId, numBlock); -+ return pluginLoop; -+} -+ - } // namespace PluginIR -\ No newline at end of file --- -2.27.0.windows.1 - diff --git a/0003-Pin-gcc-client-Support-build-CFG-CallOp-AssignOp-Con.patch b/0003-Pin-gcc-client-Support-build-CFG-CallOp-AssignOp-Con.patch deleted file mode 100644 index fabf19b..0000000 --- a/0003-Pin-gcc-client-Support-build-CFG-CallOp-AssignOp-Con.patch +++ /dev/null @@ -1,1289 +0,0 @@ -From 02138fc424b76a664ee66d55c2bafec47ba00f4e Mon Sep 17 00:00:00 2001 -From: Mingchuan Wu -Date: Thu, 8 Dec 2022 20:06:58 +0800 -Subject: [PATCH 3/4] [Pin-gcc-client] Support build CFG, CallOp, AssignOp, - CondOp and PhiOp. Add CallOp, AssignOp, CondOp and PhiOp for PluginDialect. - Now we can support CFG. - ---- - include/Dialect/CMakeLists.txt | 3 + - include/Dialect/PluginDialect.td | 39 +++ - include/Dialect/PluginOps.h | 4 + - include/Dialect/PluginOps.td | 129 ++++++++- - include/Dialect/PluginTypes.h | 4 + - include/PluginAPI/BasicPluginOpsAPI.h | 5 + - include/PluginAPI/PluginClientAPI.h | 7 + - include/PluginClient/PluginClient.h | 13 +- - include/Translate/GimpleToPluginOps.h | 64 ++-- - lib/Dialect/PluginOps.cpp | 134 +++++++++ - lib/PluginAPI/PluginClientAPI.cpp | 25 ++ - lib/PluginClient/PluginClient.cpp | 185 +++++++++++- - lib/Translate/GimpleToPluginOps.cpp | 401 +++++++++++++++++++++++++- - 13 files changed, 978 insertions(+), 35 deletions(-) - -diff --git a/include/Dialect/CMakeLists.txt b/include/Dialect/CMakeLists.txt -index f0dfc58..f44e77c 100644 ---- a/include/Dialect/CMakeLists.txt -+++ b/include/Dialect/CMakeLists.txt -@@ -1,5 +1,8 @@ - # Add for the dialect operations. arg:(dialect dialect_namespace) - file(COPY /usr/bin/mlir-tblgen DESTINATION ./) -+set(LLVM_TARGET_DEFINITIONS PluginOps.td) -+mlir_tablegen(PluginOpsEnums.h.inc -gen-enum-decls) -+mlir_tablegen(PluginOpsEnums.cpp.inc -gen-enum-defs) - add_mlir_dialect(PluginOps Plugin) - - # Necessary to generate documentation. arg:(doc_filename command output_file output_directory) -diff --git a/include/Dialect/PluginDialect.td b/include/Dialect/PluginDialect.td -index 603f2fc..b6bf728 100644 ---- a/include/Dialect/PluginDialect.td -+++ b/include/Dialect/PluginDialect.td -@@ -48,4 +48,43 @@ def Plugin_Dialect : Dialect { - class Plugin_Op traits = []> : - Op; - -+//===----------------------------------------------------------------------===// -+// PluginDialect enum definitions -+//===----------------------------------------------------------------------===// -+ -+def IComparisonLT : I32EnumAttrCase<"lt", 0>; -+def IComparisonLE : I32EnumAttrCase<"le", 1>; -+def IComparisonGT : I32EnumAttrCase<"gt", 2>; -+def IComparisonGE : I32EnumAttrCase<"ge", 3>; -+def IComparisonLTGT : I32EnumAttrCase<"ltgt", 4>; -+def IComparisonEQ : I32EnumAttrCase<"eq", 5>; -+def IComparisonNE : I32EnumAttrCase<"ne", 6>; -+def IComparisonUNDEF : I32EnumAttrCase<"UNDEF", 7>; -+def IComparisonAttr : I32EnumAttr< -+ "IComparisonCode", "plugin comparison code", -+ [IComparisonLT, IComparisonLE, IComparisonGT, IComparisonGE, -+ IComparisonLTGT, IComparisonEQ, IComparisonNE, IComparisonUNDEF]>{ -+ let cppNamespace = "::mlir::Plugin"; -+} -+ -+def IDefineCodeMemRef : I32EnumAttrCase<"MemRef", 0>; -+def IDefineCodeIntCST : I32EnumAttrCase<"IntCST", 1>; -+def IDefineCodeSSA : I32EnumAttrCase<"SSA", 2>; -+def IDefineCodeUNDEF : I32EnumAttrCase<"UNDEF", 3>; -+def IDefineCodeAttr : I32EnumAttr< -+ "IDefineCode", "plugin define code", -+ [IDefineCodeMemRef, IDefineCodeIntCST, IDefineCodeUNDEF]>{ -+ let cppNamespace = "::mlir::Plugin"; -+} -+ -+def IExprCodePlus : I32EnumAttrCase<"Plus", 0>; -+def IExprCodeMinus : I32EnumAttrCase<"Minus", 1>; -+def IExprCodeNop : I32EnumAttrCase<"Nop", 2>; -+def IExprCodeUNDEF : I32EnumAttrCase<"UNDEF", 3>; -+def IExprCodeAttr : I32EnumAttr< -+ "IExprCode", "plugin expr code", -+ [IExprCodePlus, IExprCodeMinus, IExprCodeNop, IExprCodeUNDEF]>{ -+ let cppNamespace = "::mlir::Plugin"; -+} -+ - #endif // PLUGIN_DIALECT_TD -\ No newline at end of file -diff --git a/include/Dialect/PluginOps.h b/include/Dialect/PluginOps.h -index 825310a..25089fe 100644 ---- a/include/Dialect/PluginOps.h -+++ b/include/Dialect/PluginOps.h -@@ -29,6 +29,10 @@ - #include "mlir/IR/Dialect.h" - #include "mlir/IR/OpDefinition.h" - #include "mlir/Interfaces/SideEffectInterfaces.h" -+#include "mlir/Interfaces/CallInterfaces.h" -+ -+// Pull in all enum type definitions and utility function declarations. -+#include "Dialect/PluginOpsEnums.h.inc" - - #define GET_OP_CLASSES - #include "Dialect/PluginOps.h.inc" -diff --git a/include/Dialect/PluginOps.td b/include/Dialect/PluginOps.td -index 8264555..6f4a399 100644 ---- a/include/Dialect/PluginOps.td -+++ b/include/Dialect/PluginOps.td -@@ -22,6 +22,7 @@ - - include "PluginDialect.td" - include "mlir/Interfaces/SideEffectInterfaces.td" -+include "mlir/Interfaces/CallInterfaces.td" - - def FunctionOp : Plugin_Op<"function", [NoSideEffect]> { - let summary = "function with a region"; -@@ -29,8 +30,8 @@ def FunctionOp : Plugin_Op<"function", [NoSideEffect]> { - TODO. - }]; - -- let arguments = (ins OptionalAttr:$id, -- OptionalAttr:$funcName, -+ let arguments = (ins UI64Attr:$id, -+ StrAttr:$funcName, - OptionalAttr:$declaredInline); - let regions = (region AnyRegion:$bodyRegion); - -@@ -74,5 +75,129 @@ def LoopOp : Plugin_Op<"loop", [NoSideEffect]> { - ]; - } - -+def CallOp : Plugin_Op<"call", [ -+ DeclareOpInterfaceMethods]> { -+ let summary = "call operation"; -+ let description = [{ -+ CallOp represent calls to a user defined function that needs to -+ be specialized for the shape of its arguments. -+ The callee name is attached as a symbol reference via an attribute. -+ The arguments list must match the arguments expected by the callee. -+ }]; -+ let arguments = (ins UI64Attr:$id, -+ FlatSymbolRefAttr:$callee, -+ Variadic:$inputs); -+ let results = (outs Optional:$result); -+ let builders = [ -+ OpBuilderDAG<(ins "uint64_t":$id, "StringRef":$callee, -+ "ArrayRef":$arguments)> -+ ]; -+ let assemblyFormat = [{ -+ $callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results) -+ }]; -+} -+ -+def PhiOp : Plugin_Op<"phi", [NoSideEffect]> { -+ let summary = "phi op"; -+ let description = [{TODO}]; -+ let arguments = (ins UI64Attr:$id, -+ UI32Attr:$capacity, -+ UI32Attr:$nArgs, -+ Variadic:$operands); -+ let results = (outs AnyType:$result); -+ let builders = [ -+ OpBuilderDAG<(ins "uint64_t":$id, "uint32_t":$capacity, -+ "uint32_t":$nArgs, "ArrayRef":$operands, -+ "Type":$resultType)> -+ ]; -+} -+ -+def AssignOp : Plugin_Op<"assign", [NoSideEffect]> { -+ let summary = "assign op"; -+ let description = [{TODO}]; -+ let arguments = (ins UI64Attr:$id, -+ IExprCodeAttr:$exprCode, -+ Variadic:$operands); -+ let results = (outs AnyType:$result); -+ let builders = [ -+ OpBuilderDAG<(ins "uint64_t":$id, "IExprCode":$exprCode, -+ "ArrayRef":$operands, "Type":$resultType)> -+ ]; -+ // Specify a parser and printer method. -+ // let parser = [{ return ::parseAssignOp(parser, result); }]; -+ // let printer = [{ return ::print(p, *this); }]; -+} -+ -+def PlaceholderOp : Plugin_Op<"placeholder", [NoSideEffect]> { -+ let summary = "PlaceHolder."; -+ let description = [{TODO}]; -+ let arguments = (ins UI64Attr:$id, -+ OptionalAttr:$defCode); -+ let results = (outs AnyType); -+ let builders = [ -+ OpBuilderDAG<(ins "uint64_t":$id, "IDefineCode":$defCode, "Type":$retType)> -+ ]; -+} -+ -+def BaseOp : Plugin_Op<"statement_base", [NoSideEffect]> { -+ let summary = "Base operation, just like placeholder for statement."; -+ let description = [{TODO}]; -+ let arguments = (ins UI64Attr:$id, StrAttr:$opCode); -+ let results = (outs AnyType); -+ let builders = [ -+ OpBuilderDAG<(ins "uint64_t":$id, "StringRef":$opCode)> -+ ]; -+} -+ -+// Terminators -+// Opaque builder used for terminator operations that contain successors. -+ -+class Plugin_TerminatorOp traits = []> : -+ Plugin_Op; -+ -+def FallThroughOp : Plugin_TerminatorOp<"fallthrough", [NoSideEffect]> { -+ let summary = "FallThroughOp"; -+ let description = [{TODO}]; -+ let successors = (successor AnySuccessor:$dest); -+ // for bb address -+ let arguments = (ins UI64Attr:$address, UI64Attr:$destaddr); -+ let results = (outs AnyType); -+ let builders = [ -+ OpBuilderDAG<(ins "uint64_t":$address, "Block*":$dest, "uint64_t":$destaddr)> -+ ]; -+} -+ -+def CondOp : Plugin_TerminatorOp<"condition", [NoSideEffect]> { -+ let summary = "condition op"; -+ let description = [{TODO}]; -+ let arguments = (ins UI64Attr:$id, UI64Attr:$address, -+ IComparisonAttr:$condCode, -+ AnyType:$LHS, AnyType:$RHS, -+ UI64Attr:$tbaddr, UI64Attr:$fbaddr, -+ OptionalAttr:$trueLabel, -+ OptionalAttr:$falseLabel); -+ let successors = (successor AnySuccessor:$tb, AnySuccessor:$fb); -+ let builders = [ -+ OpBuilderDAG<(ins "uint64_t":$id, "uint64_t":$address, "IComparisonCode":$condCode, -+ "Value":$lhs, "Value":$rhs, "Block*":$tb, "Block*":$fb, -+ "uint64_t":$tbaddr, "uint64_t":$fbaddr, "Value":$trueLabel, -+ "Value":$falseLabel)> -+ ]; -+ let extraClassDeclaration = [{ -+ Value GetLHS() { return getOperand(0); } -+ Value GetRHS() { return getOperand(1); } -+ }]; -+} -+ -+// todo: currently RetOp do not have a correct assemblyFormat -+def RetOp : Plugin_TerminatorOp<"ret", [NoSideEffect]> { -+ let summary = "RetOp"; -+ let description = [{TODO}]; -+ let arguments = (ins UI64Attr:$address); // for bb address -+ let results = (outs AnyType); -+ let builders = [ -+ OpBuilderDAG<(ins "uint64_t":$address)> -+ ]; -+} - - #endif // PLUGIN_OPS_TD -\ No newline at end of file -diff --git a/include/Dialect/PluginTypes.h b/include/Dialect/PluginTypes.h -index 1b4883f..e0ef867 100644 ---- a/include/Dialect/PluginTypes.h -+++ b/include/Dialect/PluginTypes.h -@@ -141,6 +141,10 @@ public: - - }; // class PluginBooleanType - -+//===----------------------------------------------------------------------===// -+// Printing and parsing. TODO -+//===----------------------------------------------------------------------===// -+ - } // namespace PluginIR - - #endif // MLIR_DIALECT_PLUGINIR_PLUGINTYPES_H_ -\ No newline at end of file -diff --git a/include/PluginAPI/BasicPluginOpsAPI.h b/include/PluginAPI/BasicPluginOpsAPI.h -index 1037bf5..f5d7e91 100644 ---- a/include/PluginAPI/BasicPluginOpsAPI.h -+++ b/include/PluginAPI/BasicPluginOpsAPI.h -@@ -55,6 +55,11 @@ public: - virtual vector > GetLoopExits(uint64_t) = 0; - virtual std::pair GetLoopSingleExit(uint64_t) = 0; - virtual LoopOp GetBlockLoopFather(uint64_t) = 0; -+ virtual PhiOp GetPhiOp(uint64_t) = 0; -+ virtual CallOp GetCallOp(uint64_t) = 0; -+ virtual bool SetLhsInCallOp(uint64_t, uint64_t) = 0; -+ virtual uint64_t CreateCondOp(IComparisonCode, uint64_t, uint64_t) = 0; -+ virtual mlir::Value GetResultFromPhi(uint64_t) = 0; - }; // class BasicPluginOpsAPI - } // namespace PluginAPI - -diff --git a/include/PluginAPI/PluginClientAPI.h b/include/PluginAPI/PluginClientAPI.h -index 42d56ee..b33fdcb 100644 ---- a/include/PluginAPI/PluginClientAPI.h -+++ b/include/PluginAPI/PluginClientAPI.h -@@ -47,6 +47,13 @@ public: - vector > GetLoopExits(uint64_t) override; - std::pair GetLoopSingleExit(uint64_t) override; - LoopOp GetBlockLoopFather(uint64_t) override; -+ PhiOp GetPhiOp(uint64_t) override; -+ CallOp GetCallOp(uint64_t) override; -+ /* Plugin API for CallOp. */ -+ bool SetLhsInCallOp(uint64_t, uint64_t) override; -+ /* Plugin API for CondOp. */ -+ uint64_t CreateCondOp(IComparisonCode, uint64_t, uint64_t) override; -+ mlir::Value GetResultFromPhi(uint64_t) override; - - private: - PluginIR::GimpleToPluginOps gimpleConversion; -diff --git a/include/PluginClient/PluginClient.h b/include/PluginClient/PluginClient.h -index 3e48c44..b18ecc0 100644 ---- a/include/PluginClient/PluginClient.h -+++ b/include/PluginClient/PluginClient.h -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - - #include "Dialect/PluginOps.h" - #include "Dialect/PluginTypes.h" -@@ -107,7 +108,6 @@ public: - /* 获取client对象实例,有且只有一个实例对象 */ - static std::shared_ptr GetInstance(void); - void OpJsonSerialize(vector& data, string& out); -- void LocalDeclsJsonSerialize(vector& decls, string& out); - void LoopOpsJsonSerialize(vector& loops, string& out); - void LoopOpJsonSerialize(mlir::Plugin::LoopOp& loop, string& out); - void BoolResultJsonSerialize(bool, string&); -@@ -116,6 +116,17 @@ public: - void EdgesJsonSerialize(vector >&, string&); - void EdgeJsonSerialize(pair&, string&); - void NopJsonSerialize(string&); -+ void FunctionOpJsonSerialize(vector& data, string& out); -+ void LocalDeclsJsonSerialize(vector& decls, string& out); -+ Json::Value OperationJsonSerialize(mlir::Operation *, uint64_t&); -+ Json::Value CallOpJsonSerialize(mlir::Plugin::CallOp& data); -+ Json::Value CondOpJsonSerialize(mlir::Plugin::CondOp& data, uint64_t&); -+ Json::Value PhiOpJsonSerialize(mlir::Plugin::PhiOp& data); -+ Json::Value AssignOpJsonSerialize(mlir::Plugin::AssignOp& data); -+ Json::Value BaseOpJsonSerialize(mlir::Plugin::BaseOp data); -+ Json::Value FallThroughOpJsonSerialize(mlir::Plugin::FallThroughOp data, uint64_t&); -+ Json::Value RetOpJsonSerialize(mlir::Plugin::RetOp data, uint64_t&); -+ Json::Value ValueJsonSerialize(mlir::Value value); - /* 将Type类型数据序列化 */ - void TypeJsonSerialize(PluginIR::PluginTypeBase& type, string& out); - /* 获取gcc插件数据并进行IR转换,将转换后的数据序列化返回给server。param:函数入参序列化后的数据 */ -diff --git a/include/Translate/GimpleToPluginOps.h b/include/Translate/GimpleToPluginOps.h -index 3f4f96a..0fd2fd2 100644 ---- a/include/Translate/GimpleToPluginOps.h -+++ b/include/Translate/GimpleToPluginOps.h -@@ -23,7 +23,7 @@ - #ifndef GIMPLE_TO_PLUGINOPS_H - #define GIMPLE_TO_PLUGINOPS_H - --#include "Translate/ToPluginOpsInterface.h" -+#include "Dialect/PluginOps.h" - #include "Translate/TypeTranslation.h" - - #include "mlir/IR/Attributes.h" -@@ -31,35 +31,59 @@ - #include "mlir/IR/BuiltinOps.h" - #include "mlir/IR/BuiltinTypes.h" - #include "mlir/IR/MLIRContext.h" -+#include "mlir/IR/Block.h" -+#include "mlir/IR/Region.h" - - namespace PluginIR { - using std::vector; -+using namespace mlir::Plugin; - --class GimpleToPluginOps : public ToPluginOpsInterface { -+namespace detail { -+ class BlockFromGimpleTranslatorImpl; -+ // class BlockToPluginIRTranslatorImpl; -+} // namespace detail -+ -+class GimpleToPluginOps { - public: -- GimpleToPluginOps (mlir::MLIRContext &context) : builder(&context) , typeTranslator(context) {} -- GimpleToPluginOps () = default; -- ~GimpleToPluginOps () = default; -+ GimpleToPluginOps (mlir::MLIRContext &); -+ ~GimpleToPluginOps (); - - /* ToPluginInterface */ -- vector GetAllFunction() override; -- vector GetAllDecls(uint64_t) override; -- vector GetAllLoops(uint64_t) override; -- LoopOp GetLoop(uint64_t) override; -- bool IsBlockInside(uint64_t, uint64_t) override; -- vector GetBlocksInLoop(uint64_t) override; -- uint64_t AllocateNewLoop(void) override; -- void DeleteLoop(uint64_t) override; -- void AddLoop (uint64_t, uint64_t, uint64_t) override; -- uint64_t GetHeader(uint64_t) override; -- uint64_t GetLatch(uint64_t) override; -- vector > GetLoopExits(uint64_t) override; -- std::pair GetLoopSingleExit(uint64_t) override; -- LoopOp GetBlockLoopFather(uint64_t) override; -+ vector GetAllFunction(); -+ vector GetAllDecls(uint64_t); -+ vector GetAllLoops(uint64_t); -+ LoopOp GetLoop(uint64_t); -+ bool IsBlockInside(uint64_t, uint64_t); -+ vector GetBlocksInLoop(uint64_t); -+ uint64_t AllocateNewLoop(void); -+ void DeleteLoop(uint64_t); -+ void AddLoop (uint64_t, uint64_t, uint64_t); -+ uint64_t GetHeader(uint64_t); -+ uint64_t GetLatch(uint64_t); -+ vector > GetLoopExits(uint64_t); -+ std::pair GetLoopSingleExit(uint64_t); -+ LoopOp GetBlockLoopFather(uint64_t); -+ CallOp BuildCallOp(uint64_t); -+ bool SetGimpleCallLHS(uint64_t, uint64_t); -+ uint64_t CreateGcond(IComparisonCode, uint64_t, uint64_t); -+ FunctionOp BuildFunctionOp(uint64_t); -+ Operation *BuildOperation(uint64_t); -+ CondOp BuildCondOp(uint64_t, uint64_t, Block*, Block*, uint64_t, uint64_t); -+ AssignOp BuildAssignOp(uint64_t); -+ PhiOp BuildPhiOp(uint64_t); -+ mlir::Value GetGphiResult(uint64_t); -+ mlir::Value TreeToValue(uint64_t); -+ - private: -+ GimpleToPluginOps () = delete; - mlir::OpBuilder builder; - TypeFromPluginIRTranslator typeTranslator; -+ -+ // process basic_block -+ std::unique_ptr bbTranslator; -+ bool ProcessBasicBlock(intptr_t, Region&); -+ bool ProcessGimpleStmt(intptr_t, Region&); - }; - } // namespace PluginIR - --#endif // GIMPLE_TO_PLUGINOPS_H -\ No newline at end of file -+#endif // GIMPLE_TO_PLUGINOPS_H -diff --git a/lib/Dialect/PluginOps.cpp b/lib/Dialect/PluginOps.cpp -index adf7ca6..de5cd11 100644 ---- a/lib/Dialect/PluginOps.cpp -+++ b/lib/Dialect/PluginOps.cpp -@@ -61,6 +61,140 @@ void LoopOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, - builder.getI32IntegerAttr(numBlock)); - } - -+//===----------------------------------------------------------------------===// -+// PlaceholderOp -+ -+void PlaceholderOp::build(OpBuilder &builder, OperationState &state, -+ uint64_t id, IDefineCode defCode, Type retType) { -+ state.addAttribute("id", builder.getI64IntegerAttr(id)); -+ state.addAttribute("defCode", -+ builder.getI32IntegerAttr(static_cast(defCode))); -+ if (retType) state.addTypes(retType); -+} -+ -+//===----------------------------------------------------------------------===// -+// CallOp -+ -+void CallOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, -+ uint64_t id, StringRef callee, -+ ArrayRef arguments) { -+ state.addAttribute("id", builder.getI64IntegerAttr(id)); -+ state.addOperands(arguments); -+ state.addAttribute("callee", builder.getSymbolRefAttr(callee)); -+} -+ -+/// Return the callee of the generic call operation, this is required by the -+/// call interface. -+CallInterfaceCallable CallOp::getCallableForCallee() { -+ return (*this)->getAttrOfType("callee"); -+} -+ -+/// Get the argument operands to the called function, this is required by the -+/// call interface. -+Operation::operand_range CallOp::getArgOperands() { return inputs(); } -+ -+//===----------------------------------------------------------------------===// -+// CondOp -+ -+void CondOp::build(OpBuilder &builder, OperationState &state, -+ uint64_t id, uint64_t address, IComparisonCode condCode, -+ Value lhs, Value rhs, Block* tb, Block* fb, uint64_t tbaddr, -+ uint64_t fbaddr, Value trueLabel, Value falseLabel) { -+ state.addAttribute("id", builder.getI64IntegerAttr(id)); -+ state.addAttribute("address", builder.getI64IntegerAttr(address)); -+ state.addOperands({lhs, rhs}); -+ state.addAttribute("tbaddr", builder.getI64IntegerAttr(tbaddr)); -+ state.addAttribute("fbaddr", builder.getI64IntegerAttr(fbaddr)); -+ state.addSuccessors(tb); -+ state.addSuccessors(fb); -+ state.addAttribute("condCode", -+ builder.getI32IntegerAttr(static_cast(condCode))); -+ if (trueLabel != nullptr) state.addOperands(trueLabel); -+ if (falseLabel != nullptr) state.addOperands(falseLabel); -+} -+ -+//===----------------------------------------------------------------------===// -+// PhiOp -+ -+void PhiOp::build(OpBuilder &builder, OperationState &state, -+ uint64_t id, uint32_t capacity, uint32_t nArgs, -+ ArrayRef operands, Type resultType) { -+ state.addAttribute("id", builder.getI64IntegerAttr(id)); -+ state.addAttribute("capacity", builder.getI32IntegerAttr(capacity)); -+ state.addAttribute("nArgs", builder.getI32IntegerAttr(nArgs)); -+ state.addOperands(operands); -+ if (resultType) state.addTypes(resultType); -+} -+ -+//===----------------------------------------------------------------------===// -+// AssignOp -+ -+void AssignOp::build(OpBuilder &builder, OperationState &state, -+ uint64_t id, IExprCode exprCode, -+ ArrayRef operands, Type resultType) -+{ -+ state.addAttribute("id", builder.getI64IntegerAttr(id)); -+ state.addAttribute("exprCode", -+ builder.getI32IntegerAttr(static_cast(exprCode))); -+ state.addOperands(operands); -+ if (resultType) state.addTypes(resultType); -+} -+ -+/// The 'OpAsmParser' class provides a collection of methods for parsing -+/// various punctuation, as well as attributes, operands, types, etc. Each of -+/// these methods returns a `ParseResult`. This class is a wrapper around -+/// `LogicalResult` that can be converted to a boolean `true` value on failure, -+/// or `false` on success. This allows for easily chaining together a set of -+/// parser rules. These rules are used to populate an `mlir::OperationState` -+/// similarly to the `build` methods described above. -+static mlir::ParseResult parseAssignOp(mlir::OpAsmParser &parser, -+ mlir::OperationState &result) { -+ mlir::DenseElementsAttr value; -+ if (parser.parseOptionalAttrDict(result.attributes) || -+ parser.parseAttribute(value, "value", result.attributes)) -+ return failure(); -+ -+ result.addTypes(value.getType()); -+ return success(); -+} -+ -+/// The 'OpAsmPrinter' class is a stream that allows for formatting -+/// strings, attributes, operands, types, etc. -+static void print(mlir::OpAsmPrinter &printer, AssignOp op) { -+ printer << "assign "; -+ printer.printType(op.getType()); -+// printer << op.value(); -+} -+ -+//===----------------------------------------------------------------------===// -+// BaseOp -+ -+void BaseOp::build(OpBuilder &builder, OperationState &state, -+ uint64_t id, StringRef opCode) -+{ -+ state.addAttribute("id", builder.getI64IntegerAttr(id)); -+ state.addAttribute("opCode", builder.getStringAttr(opCode)); -+} -+ -+//===----------------------------------------------------------------------===// -+// FallThroughOp -+ -+void FallThroughOp::build(OpBuilder &builder, OperationState &state, -+ uint64_t address, Block* dest, uint64_t destaddr) -+{ -+ state.addAttribute("address", builder.getI64IntegerAttr(address)); -+ state.addAttribute("destaddr", builder.getI64IntegerAttr(destaddr)); -+ state.addSuccessors(dest); -+} -+ -+//===----------------------------------------------------------------------===// -+// RetOp -+ -+void RetOp::build(OpBuilder &builder, OperationState &state, uint64_t address) -+{ -+ state.addAttribute("address", builder.getI64IntegerAttr(address)); -+} -+ - //===----------------------------------------------------------------------===// - // TableGen'd op method definitions - //===----------------------------------------------------------------------===// -diff --git a/lib/PluginAPI/PluginClientAPI.cpp b/lib/PluginAPI/PluginClientAPI.cpp -index d268c1e..ece137f 100644 ---- a/lib/PluginAPI/PluginClientAPI.cpp -+++ b/lib/PluginAPI/PluginClientAPI.cpp -@@ -86,5 +86,30 @@ LoopOp PluginClientAPI::GetBlockLoopFather(uint64_t blockId) - { - return gimpleConversion.GetBlockLoopFather(blockId); - } -+PhiOp PluginClientAPI::GetPhiOp(uint64_t id) -+{ -+ return gimpleConversion.BuildPhiOp(id); -+} -+ -+CallOp PluginClientAPI::GetCallOp(uint64_t id) -+{ -+ return gimpleConversion.BuildCallOp(id); -+} -+ -+bool PluginClientAPI::SetLhsInCallOp(uint64_t callId, uint64_t lhsId) -+{ -+ return gimpleConversion.SetGimpleCallLHS(callId, lhsId); -+} -+ -+uint64_t PluginClientAPI::CreateCondOp(IComparisonCode iCode, -+ uint64_t LHS, uint64_t RHS) -+{ -+ return gimpleConversion.CreateGcond(iCode, LHS, RHS); -+} -+ -+mlir::Value PluginClientAPI::GetResultFromPhi(uint64_t id) -+{ -+ return gimpleConversion.GetGphiResult(id); -+} - - } // namespace PluginAPI -\ No newline at end of file -diff --git a/lib/PluginClient/PluginClient.cpp b/lib/PluginClient/PluginClient.cpp -index c57d36c..e8a7d7d 100644 ---- a/lib/PluginClient/PluginClient.cpp -+++ b/lib/PluginClient/PluginClient.cpp -@@ -31,7 +31,6 @@ - #include - #include - #include --#include - - namespace PinClient { - using namespace mlir::Plugin; -@@ -106,7 +105,7 @@ void PluginClient::TypeJsonSerialize (PluginIR::PluginTypeBase& type, string& ou - out = root.toStyledString(); - } - --void PluginClient::OpJsonSerialize(vector& data, string& out) -+void PluginClient::FunctionOpJsonSerialize(vector& data, string& out) - { - Json::Value root; - Json::Value operationObj; -@@ -122,14 +121,77 @@ void PluginClient::OpJsonSerialize(vector& data, string& out) - item["attributes"]["declaredInline"] = "1"; - else - item["attributes"]["declaredInline"] = "0"; -- item["attributes"]["funcName"] = d.funcNameAttr().getValue().str(); -- operation = "operation" + std::to_string(i++); -+ item["attributes"]["funcName"] = d.funcNameAttr().getValue().str().c_str(); -+ auto ®ion = d.getRegion(); -+ size_t bbIdx = 0; -+ for (auto &b : region) { -+ string blockStr = "block" + std::to_string(bbIdx++); -+ uint64_t bbAddress = 0; -+ size_t opIdx = 0; -+ for (auto &inst : b) { -+ if (auto phOp = llvm::dyn_cast(inst)) continue; -+ string opStr = "Operation" + std::to_string(opIdx++); -+ item["region"][blockStr]["ops"][opStr] = OperationJsonSerialize(&inst, bbAddress); -+ } -+ assert(bbAddress != 0); -+ item["region"][blockStr]["address"] = std::to_string(bbAddress); -+ } -+ operation = "FunctionOp" + std::to_string(i++); - root[operation] = item; - item.clear(); - } - out = root.toStyledString(); - } - -+Json::Value PluginClient::OperationJsonSerialize(mlir::Operation *operation, -+ uint64_t &bbId) -+{ -+ Json::Value root; -+ if (AssignOp op = llvm::dyn_cast(operation)) { -+ root = AssignOpJsonSerialize(op); -+ } else if (CallOp op = llvm::dyn_cast(operation)) { -+ root = CallOpJsonSerialize(op); -+ } else if (CondOp op = llvm::dyn_cast(operation)) { -+ root = CondOpJsonSerialize(op, bbId); -+ } else if (PhiOp op = llvm::dyn_cast(operation)) { -+ root = PhiOpJsonSerialize(op); -+ } else if (FallThroughOp op = llvm::dyn_cast(operation)) { -+ root = FallThroughOpJsonSerialize(op, bbId); -+ } else if (RetOp op = llvm::dyn_cast(operation)) { -+ root = RetOpJsonSerialize(op, bbId); -+ } else if (BaseOp op = llvm::dyn_cast(operation)) { -+ root = BaseOpJsonSerialize(op); -+ } -+ root["OperationName"] = operation->getName().getStringRef().str(); -+ return root; -+} -+ -+Json::Value PluginClient::BaseOpJsonSerialize(BaseOp data) -+{ -+ Json::Value root; -+ root["id"] = std::to_string(data.idAttr().getInt()); -+ root["opCode"] = data.opCodeAttr().getValue().str().c_str(); -+ return root; -+} -+ -+Json::Value PluginClient::RetOpJsonSerialize(RetOp data, uint64_t &bbId) -+{ -+ Json::Value root; -+ bbId = data.addressAttr().getInt(); -+ root["address"] = std::to_string(bbId); -+ return root; -+} -+ -+Json::Value PluginClient::FallThroughOpJsonSerialize(FallThroughOp data, -+ uint64_t &bbId) -+{ -+ Json::Value root; -+ bbId = data.addressAttr().getInt(); -+ root["address"] = std::to_string(bbId); -+ root["destaddr"] = std::to_string(data.destaddrAttr().getInt()); -+ return root; -+} -+ - void PluginClient::LocalDeclsJsonSerialize(vector& decls, string& out) - { - Json::Value root; -@@ -245,6 +307,78 @@ void PluginClient::NopJsonSerialize(string& out) - out = root.toStyledString(); - } - -+Json::Value PluginClient::CallOpJsonSerialize(CallOp& data) -+{ -+ Json::Value item; -+ item["id"] = std::to_string(data.idAttr().getInt()); -+ item["callee"] = data.callee().str(); -+ size_t opIdx = 0; -+ for (mlir::Value v : data.getArgOperands()) { -+ PlaceholderOp phOp = v.getDefiningOp(); -+ string input = "input" + std::to_string(opIdx++); -+ item["operands"][input]["id"] = std::to_string(phOp.idAttr().getInt()); -+ item["operands"][input]["defCode"] = std::to_string(phOp.defCodeAttr().getInt()); -+ } -+ return item; -+} -+ -+Json::Value PluginClient::CondOpJsonSerialize(CondOp& data, uint64_t &bbId) -+{ -+ Json::Value item; -+ item["id"] = std::to_string(data.idAttr().getInt()); -+ item["condCode"] = std::to_string(data.condCodeAttr().getInt()); -+ item["lhs"] = ValueJsonSerialize(data.GetLHS()); -+ item["rhs"] = ValueJsonSerialize(data.GetRHS()); -+ bbId = data.addressAttr().getInt(); -+ item["address"] = std::to_string(bbId); -+ item["tbaddr"] = std::to_string(data.tbaddrAttr().getInt()); -+ item["fbaddr"] = std::to_string(data.fbaddrAttr().getInt()); -+ return item; -+} -+ -+Json::Value PluginClient::PhiOpJsonSerialize(PhiOp& data) -+{ -+ Json::Value item; -+ item["id"] = std::to_string(data.idAttr().getInt()); -+ item["capacity"] = std::to_string(data.capacityAttr().getInt()); -+ item["nArgs"] = std::to_string(data.nArgsAttr().getInt()); -+ size_t opIdx = 0; -+ for (mlir::Value v : data.operands()) { -+ PlaceholderOp phOp = v.getDefiningOp(); -+ string input = "input" + std::to_string(opIdx++); -+ item["operands"][input]["id"] = std::to_string(phOp.idAttr().getInt()); -+ item["operands"][input]["defCode"] = std::to_string(phOp.defCodeAttr().getInt()); -+ } -+ return item; -+} -+ -+Json::Value PluginClient::AssignOpJsonSerialize(AssignOp& data) -+{ -+ Json::Value item; -+ item["id"] = std::to_string(data.idAttr().getInt()); -+ item["exprCode"] = std::to_string(data.exprCodeAttr().getInt()); -+ size_t opIdx = 0; -+ for (mlir::Value v : data.operands()) { -+ PlaceholderOp phOp = v.getDefiningOp(); -+ string input = "input" + std::to_string(opIdx++); -+ item["operands"][input]["id"] = std::to_string(phOp.idAttr().getInt()); -+ item["operands"][input]["defCode"] = std::to_string(phOp.defCodeAttr().getInt()); -+ } -+ return item; -+} -+ -+Json::Value PluginClient::ValueJsonSerialize(mlir::Value data) -+{ -+ Json::Value root; -+ if (PlaceholderOp phOp = data.getDefiningOp()) { -+ root["id"] = std::to_string(phOp.idAttr().getInt()); -+ root["defCode"] = std::to_string(phOp.defCodeAttr().getInt()); -+ } else { -+ LOGE("ERROR: Can't Serialize!"); -+ } -+ return root; -+} -+ - void PluginClient::IRTransBegin(const string& funcName, const string& param) - { - string result; -@@ -260,7 +394,7 @@ void PluginClient::IRTransBegin(const string& funcName, const string& param) - context.getOrLoadDialect(); - PluginAPI::PluginClientAPI clientAPI(context); - vector allFuncOps = clientAPI.GetAllFunc(); -- OpJsonSerialize(allFuncOps, result); -+ FunctionOpJsonSerialize(allFuncOps, result); - this->ReceiveSendMsg("FuncOpResult", result); - } else if (funcName == "GetLocalDecls") { - /// Json格式 -@@ -436,6 +570,47 @@ void PluginClient::IRTransBegin(const string& funcName, const string& param) - LoopOp loopFather = clientAPI.GetBlockLoopFather(blockId); - LoopOpJsonSerialize(loopFather, result); - this->ReceiveSendMsg("LoopOpResult", result); -+ } else if (funcName == "GetPhiOp") { -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ uint64_t id = atol(root[std::to_string(0)].asString().c_str()); -+ PhiOp op = clientAPI.GetPhiOp(id); -+ Json::Value result = PhiOpJsonSerialize(op); -+ this->ReceiveSendMsg("OpsResult", result.toStyledString()); -+ } else if (funcName == "GetCallOp") { -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ uint64_t id = atol(root[std::to_string(0)].asString().c_str()); -+ CallOp op = clientAPI.GetCallOp(id); -+ Json::Value result = CallOpJsonSerialize(op); -+ this->ReceiveSendMsg("OpsResult", result.toStyledString()); -+ } else if (funcName == "SetLhsInCallOp") { -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ uint64_t callId = atol(root["callId"].asString().c_str()); -+ uint64_t lhsId = atol(root["lhsId"].asString().c_str()); -+ bool ret = clientAPI.SetLhsInCallOp(callId, lhsId); -+ this->ReceiveSendMsg("BoolResult", std::to_string(ret)); -+ } else if (funcName == "CreateCondOp") { -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ int condCode = atol(root["condCode"].asString().c_str()); -+ uint64_t lhsId = atol(root["lhsId"].asString().c_str()); -+ uint64_t rhsId = atol(root["rhsId"].asString().c_str()); -+ uint64_t ret = clientAPI.CreateCondOp(IComparisonCode(condCode), -+ lhsId, rhsId); -+ this->ReceiveSendMsg("IdResult", std::to_string(ret)); -+ } else if (funcName == "GetResultFromPhi") { -+ mlir::MLIRContext context; -+ context.getOrLoadDialect(); -+ PluginAPI::PluginClientAPI clientAPI(context); -+ uint64_t id = atol(root["id"].asString().c_str()); -+ mlir::Value ret = clientAPI.GetResultFromPhi(id); -+ this->ReceiveSendMsg("ValueResult", ValueJsonSerialize(ret).toStyledString()); - } else { - LOGW("function: %s not found!\n", funcName.c_str()); - } -diff --git a/lib/Translate/GimpleToPluginOps.cpp b/lib/Translate/GimpleToPluginOps.cpp -index 273a214..1f9988b 100644 ---- a/lib/Translate/GimpleToPluginOps.cpp -+++ b/lib/Translate/GimpleToPluginOps.cpp -@@ -20,6 +20,8 @@ - #include "Dialect/PluginTypes.h" - - #include -+#include "llvm/Support/Casting.h" -+#include "llvm/ADT/SmallVector.h" - - #include "gcc-plugin.h" - #include "plugin-version.h" -@@ -46,6 +48,121 @@ - - namespace PluginIR { - using namespace mlir::Plugin; -+using namespace mlir; -+ -+namespace detail { -+class BlockFromGimpleTranslatorImpl { -+public: -+ std::map blockMaps; -+ /* Constructs a class creating types in the given MLIR context. */ -+ BlockFromGimpleTranslatorImpl(mlir::MLIRContext &context) : context(context) {} -+ -+private: -+ /* The context in which MLIR types are created. */ -+ mlir::MLIRContext &context; -+}; -+ -+} // namespace detail -+ -+GimpleToPluginOps::GimpleToPluginOps (mlir::MLIRContext &context) : -+ builder(&context), typeTranslator(context), bbTranslator(new detail::BlockFromGimpleTranslatorImpl(context)) -+{} -+ -+GimpleToPluginOps::~GimpleToPluginOps () -+{} -+ -+static IComparisonCode TranslateCmpCode(enum tree_code ccode) -+{ -+ switch (ccode) { -+ case LT_EXPR: -+ return IComparisonCode::lt; -+ case LE_EXPR: -+ return IComparisonCode::le; -+ case GT_EXPR: -+ return IComparisonCode::gt; -+ case GE_EXPR: -+ return IComparisonCode::ge; -+ case LTGT_EXPR: -+ return IComparisonCode::ltgt; -+ case EQ_EXPR: -+ return IComparisonCode::eq; -+ case NE_EXPR: -+ return IComparisonCode::ne; -+ default: -+ printf("tcc_comparison: %d not suppoted!\n", ccode); -+ break; -+ } -+ return IComparisonCode::UNDEF; -+} -+ -+static enum tree_code TranslateCmpCodeToTreeCode(IComparisonCode iCode) -+{ -+ switch (iCode) { -+ case IComparisonCode::lt: -+ return LT_EXPR; -+ case IComparisonCode::le: -+ return LE_EXPR; -+ case IComparisonCode::gt: -+ return GT_EXPR; -+ case IComparisonCode::ge: -+ return GE_EXPR; -+ case IComparisonCode::ltgt: -+ return LTGT_EXPR; -+ case IComparisonCode::eq: -+ return EQ_EXPR; -+ case IComparisonCode::ne: -+ return NE_EXPR; -+ default: -+ printf("tcc_comparison not suppoted!\n"); -+ break; -+ } -+ return LT_EXPR; -+} -+ -+static IExprCode TranslateExprCode(enum tree_code ccode) -+{ -+ switch (ccode) { -+ case PLUS_EXPR: -+ return IExprCode::Plus; -+ case MINUS_EXPR: -+ return IExprCode::Minus; -+ case NOP_EXPR: -+ return IExprCode::Nop; -+ default: -+ // printf("tcc_binary: %d not suppoted!\n", ccode); -+ break; -+ } -+ return IExprCode::UNDEF; -+} -+ -+static StringRef GimpleCodeToOperationName(enum gimple_code tcode) -+{ -+ StringRef ret; -+ switch (tcode) { -+ case GIMPLE_PHI: { -+ ret = PhiOp::getOperationName(); -+ break; -+ } -+ case GIMPLE_ASSIGN: { -+ ret = AssignOp::getOperationName(); -+ break; -+ } -+ case GIMPLE_CALL: { -+ ret = CallOp::getOperationName(); -+ break; -+ } -+ case GIMPLE_COND: { -+ ret = CondOp::getOperationName(); -+ break; -+ } -+ default: { -+ ret = BaseOp::getOperationName(); -+ break; -+ } -+ } -+ return ret; -+} -+ - vector GimpleToPluginOps::GetAllFunction() - { - cgraph_node *node = NULL; -@@ -56,14 +173,9 @@ vector GimpleToPluginOps::GetAllFunction() - if (fn == NULL) - continue; - int64_t id = reinterpret_cast(reinterpret_cast(fn)); -- FunctionOp irFunc; -- mlir::StringRef funcName(function_name(fn)); -- bool declaredInline = false; -- if (DECL_DECLARED_INLINE_P(fn->decl)) -- declaredInline = true; -- auto location = builder.getUnknownLoc(); -- irFunc = builder.create(location, id, funcName, declaredInline); -+ FunctionOp irFunc = BuildFunctionOp(id); - functions.push_back(irFunc); -+ builder.setInsertionPointAfter(irFunc.getOperation()); - } - return functions; - } -@@ -229,4 +341,279 @@ LoopOp GimpleToPluginOps::GetBlockLoopFather(uint64_t blockID) - return pluginLoop; - } - -+FunctionOp GimpleToPluginOps::BuildFunctionOp(uint64_t functionId) -+{ -+ function *fn = reinterpret_cast(functionId); -+ mlir::StringRef funcName(function_name(fn)); -+ bool declaredInline = false; -+ if (DECL_DECLARED_INLINE_P(fn->decl)) -+ declaredInline = true; -+ auto location = builder.getUnknownLoc(); -+ FunctionOp retOp = builder.create(location, functionId, -+ funcName, declaredInline); -+ auto& fr = retOp.bodyRegion(); -+ if (!ProcessBasicBlock((intptr_t)ENTRY_BLOCK_PTR_FOR_FN(fn), fr)) { -+ // handle error -+ return retOp; -+ } -+ return retOp; -+} -+ -+Operation *GimpleToPluginOps::BuildOperation(uint64_t id) -+{ -+ gimple *stmt = reinterpret_cast(id); -+ Operation *ret = nullptr; -+ switch (gimple_code(stmt)) { -+ case GIMPLE_PHI: { -+ PhiOp phiOp = BuildPhiOp(id); -+ ret = phiOp.getOperation(); -+ break; -+ } -+ case GIMPLE_ASSIGN: { -+ AssignOp assignOp = BuildAssignOp(id); -+ ret = assignOp.getOperation(); -+ break; -+ } -+ case GIMPLE_CALL: { -+ CallOp callOp = BuildCallOp(id); -+ ret = callOp.getOperation(); -+ break; -+ } -+ case GIMPLE_COND: { -+ assert(EDGE_COUNT (stmt->bb->succs) == 2); -+ Block* trueBlock = bbTranslator->blockMaps[EDGE_SUCC(stmt->bb, 0)->dest]; -+ Block* falseBlock = bbTranslator->blockMaps[EDGE_SUCC(stmt->bb, 1)->dest]; -+ CondOp condOp = BuildCondOp(id, (uint64_t)stmt->bb, -+ trueBlock, falseBlock, -+ (uint64_t)EDGE_SUCC(stmt->bb, 0)->dest, -+ (uint64_t)EDGE_SUCC(stmt->bb, 1)->dest); -+ ret = condOp.getOperation(); -+ break; -+ } -+ default: { -+ BaseOp baseOp = builder.create( -+ builder.getUnknownLoc(), id, BaseOp::getOperationName()); -+ ret = baseOp.getOperation(); -+ break; -+ } -+ } -+ return ret; -+} -+ -+PhiOp GimpleToPluginOps::BuildPhiOp(uint64_t gphiId) -+{ -+ gphi *stmt = reinterpret_cast(gphiId); -+ llvm::SmallVector ops; -+ ops.reserve(gimple_phi_num_args(stmt)); -+ for (unsigned i = 0; i < gimple_phi_num_args(stmt); i++) { -+ tree *argTree = gimple_phi_arg_def_ptr(stmt, i); -+ uint64_t argId = reinterpret_cast( -+ reinterpret_cast(argTree)); -+ Value arg = TreeToValue(argId); -+ ops.push_back(arg); -+ } -+ tree returnType = TREE_TYPE(gimple_phi_result(stmt)); -+ PluginTypeBase rPluginType = typeTranslator.translateType((intptr_t)returnType); -+ uint32_t capacity = gimple_phi_capacity(stmt); -+ uint32_t nArgs = gimple_phi_num_args(stmt); -+ PhiOp ret = builder.create(builder.getUnknownLoc(), -+ gphiId, capacity, nArgs, ops, rPluginType); -+ return ret; -+} -+ -+CallOp GimpleToPluginOps::BuildCallOp(uint64_t gcallId) -+{ -+ gcall *stmt = reinterpret_cast(gcallId); -+ tree fndecl = gimple_call_fndecl(stmt); -+ if (fndecl == NULL_TREE || DECL_NAME(fndecl) == NULL_TREE) { -+ return nullptr; -+ } -+ llvm::SmallVector ops; -+ ops.reserve(gimple_call_num_args(stmt)); -+ for (unsigned i = 0; i < gimple_call_num_args(stmt); i++) { -+ tree *callArg = gimple_call_arg_ptr(stmt, i); -+ uint64_t argId = reinterpret_cast( -+ reinterpret_cast(callArg)); -+ Value arg = TreeToValue(argId); -+ ops.push_back(arg); -+ } -+ StringRef callName(IDENTIFIER_POINTER(DECL_NAME(fndecl))); -+ tree returnType = gimple_call_return_type(stmt); -+ PluginTypeBase rPluginType = typeTranslator.translateType((intptr_t)returnType); -+ CallOp ret = builder.create(builder.getUnknownLoc(), gcallId, callName, ops); -+ return ret; -+} -+ -+bool GimpleToPluginOps::SetGimpleCallLHS(uint64_t callId, uint64_t lhsId) -+{ -+ gcall *stmt = reinterpret_cast(callId); -+ tree *lhs = reinterpret_cast(callId); -+ gimple_call_set_lhs (stmt, *lhs); -+ return true; -+} -+ -+uint64_t GimpleToPluginOps::CreateGcond(IComparisonCode iCode, -+ uint64_t lhsId, uint64_t rhsId) -+{ -+ tree *lhs = reinterpret_cast(lhsId); -+ tree *rhs = reinterpret_cast(rhsId); -+ gcond *ret = gimple_build_cond (TranslateCmpCodeToTreeCode(iCode), -+ *lhs, *rhs, NULL_TREE, NULL_TREE); -+ return reinterpret_cast(reinterpret_cast(ret)); -+} -+ -+CondOp GimpleToPluginOps::BuildCondOp(uint64_t gcondId, uint64_t address, -+ Block* b1, Block* b2, uint64_t tbaddr, -+ uint64_t fbaddr) -+{ -+ gcond *stmt = reinterpret_cast(gcondId); -+ tree *lhsPtr = gimple_cond_lhs_ptr(stmt); -+ uint64_t lhsId = reinterpret_cast( -+ reinterpret_cast(lhsPtr)); -+ Value LHS = TreeToValue(lhsId); -+ tree *rhsPtr = gimple_cond_rhs_ptr(stmt); -+ uint64_t rhsId = reinterpret_cast( -+ reinterpret_cast(rhsPtr)); -+ Value RHS = TreeToValue(rhsId); -+ Value trueLabel = nullptr; -+ Value falseLabel = nullptr; -+ IComparisonCode iCode = TranslateCmpCode(gimple_cond_code(stmt)); -+ CondOp ret = builder.create(builder.getUnknownLoc(), gcondId, -+ address, iCode, LHS, RHS, b1, b2, -+ tbaddr, fbaddr, trueLabel, falseLabel); -+ return ret; -+} -+ -+AssignOp GimpleToPluginOps::BuildAssignOp(uint64_t gassignId) -+{ -+ gassign *stmt = reinterpret_cast(gassignId); -+ llvm::SmallVector ops; -+ ops.reserve(gimple_num_ops(stmt)); -+ uint64_t lhsId = reinterpret_cast( -+ reinterpret_cast(gimple_assign_lhs_ptr(stmt))); -+ ops.push_back(TreeToValue(lhsId)); -+ uint64_t rhs1Id = reinterpret_cast( -+ reinterpret_cast(gimple_assign_rhs1_ptr(stmt))); -+ ops.push_back(TreeToValue(rhs1Id)); -+ if (gimple_assign_rhs2(stmt) != NULL_TREE) { -+ uint64_t rhs2Id = reinterpret_cast( -+ reinterpret_cast(gimple_assign_rhs2_ptr(stmt))); -+ ops.push_back(TreeToValue(rhs2Id)); -+ } -+ if (gimple_assign_rhs3(stmt) != NULL_TREE) { -+ uint64_t rhs3Id = reinterpret_cast( -+ reinterpret_cast(gimple_assign_rhs3_ptr(stmt))); -+ ops.push_back(TreeToValue(rhs3Id)); -+ } -+ IExprCode iCode = TranslateExprCode(gimple_assign_rhs_code(stmt)); -+ mlir::Type returnType = nullptr; -+ AssignOp ret = builder.create( -+ builder.getUnknownLoc(), gassignId, iCode, ops, returnType); -+ return ret; -+} -+ -+Value GimpleToPluginOps::GetGphiResult(uint64_t id) -+{ -+ gphi *stmt = reinterpret_cast(id); -+ tree ret = gimple_phi_result(stmt); -+ uint64_t retId = reinterpret_cast( -+ reinterpret_cast(ret)); -+ return TreeToValue(retId); -+} -+ -+Value GimpleToPluginOps::TreeToValue(uint64_t treeId) -+{ -+ tree *t = reinterpret_cast(treeId); -+ tree treeType = TREE_TYPE(*t); -+ PluginTypeBase rPluginType = typeTranslator.translateType((intptr_t)treeType); -+ switch (TREE_CODE(*t)) { -+ case MEM_REF : { -+ break; -+ } -+ case INTEGER_CST : { -+ break; -+ } -+ case SSA_NAME : { -+ break; -+ } -+ default: -+ break; -+ } -+ mlir::Value opValue = builder.create( -+ builder.getUnknownLoc(), treeId, -+ IDefineCode::UNDEF, rPluginType); -+ return opValue; -+} -+ -+bool GimpleToPluginOps::ProcessGimpleStmt(intptr_t bbPtr, Region& rg) -+{ -+ bool putTerminator = false; -+ basic_block bb = reinterpret_cast(bbPtr); -+ for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) { -+ gphi *p = si.phi (); -+ uint64_t id = reinterpret_cast(reinterpret_cast(p)); -+ BuildPhiOp(id); // FIXME: Check result. -+ } -+ -+ for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si)) { -+ gimple *stmt = gsi_stmt (si); -+ uint64_t id = reinterpret_cast(reinterpret_cast(stmt)); -+ if (BuildOperation(id) == nullptr) { -+ printf("ERROR: BuildOperation!"); -+ } -+ if(gimple_code(stmt) == GIMPLE_COND) { -+ putTerminator = true; -+ } -+ } -+ -+ if (!putTerminator) { -+ // Process fallthrough, todo: process goto -+ if (EDGE_COUNT (bb->succs) == 1) { -+ builder.create(builder.getUnknownLoc(), (uint64_t)bb, -+ bbTranslator->blockMaps[EDGE_SUCC(bb, 0)->dest], -+ (uint64_t)(EDGE_SUCC(bb, 0)->dest)); -+ } else if (!EDGE_COUNT (bb->succs)) { -+ // Process other condition, such as return -+ builder.create(builder.getUnknownLoc(), (uint64_t)bb); -+ } else { -+ // Should unreachable; -+ assert(false); -+ } -+ } -+ -+ return true; -+} -+ -+bool GimpleToPluginOps::ProcessBasicBlock(intptr_t bbPtr, Region& rg) -+{ -+ basic_block bb = reinterpret_cast(bbPtr); -+ // handled, skip process -+ if (bbTranslator->blockMaps.find(bb) != bbTranslator->blockMaps.end()) { -+ return true; -+ } -+ // fprintf(stderr,"processing bb[%d]\n", bb->index); -+ -+ // create basic block -+ Block* block = builder.createBlock(&rg, rg.begin()); -+ bbTranslator->blockMaps.insert({bb, block}); -+ // todo process func return type -+ // todo isDeclaration -+ -+ // process succ -+ for (unsigned int i = 0; i < EDGE_COUNT (bb->succs); i++) { -+ // fprintf(stderr,"-->[%d]\n", EDGE_SUCC(bb, i)->dest->index); -+ if (!ProcessBasicBlock((intptr_t)(EDGE_SUCC(bb, i)->dest), rg)) { -+ return false; -+ } -+ } -+ // process each stmt -+ builder.setInsertionPointToStart(block); -+ if (!ProcessGimpleStmt(bbPtr, rg)) { -+ return false; -+ } -+ // block->dump(); -+ // fprintf(stderr, "[bb%d] succ: %d\n", bb->index,block->getNumSuccessors()); -+ return true; -+} -+ - } // namespace PluginIR -\ No newline at end of file --- -2.27.0.windows.1 - diff --git a/0004-Pin-gcc-client-Support-Plugin-Pointer-type.patch b/0004-Pin-gcc-client-Support-Plugin-Pointer-type.patch deleted file mode 100644 index da003d6..0000000 --- a/0004-Pin-gcc-client-Support-Plugin-Pointer-type.patch +++ /dev/null @@ -1,184 +0,0 @@ -From b8322c7f689c44ac7ca5fb4d407994308f4725ed Mon Sep 17 00:00:00 2001 -From: dingguangya -Date: Thu, 8 Dec 2022 20:41:09 +0800 -Subject: [PATCH 4/4] [Pin-gcc-client] Support Plugin Pointer type - ---- - include/Dialect/PluginTypes.h | 12 +++++++++ - include/PluginClient/PluginClient.h | 2 +- - lib/Dialect/PluginDialect.cpp | 1 + - lib/Dialect/PluginTypes.cpp | 41 +++++++++++++++++++++++++++++ - lib/PluginClient/PluginClient.cpp | 9 +++++-- - lib/Translate/TypeTranslation.cpp | 2 ++ - 6 files changed, 64 insertions(+), 3 deletions(-) - -diff --git a/include/Dialect/PluginTypes.h b/include/Dialect/PluginTypes.h -index e0ef867..b329caa 100644 ---- a/include/Dialect/PluginTypes.h -+++ b/include/Dialect/PluginTypes.h -@@ -80,6 +80,7 @@ private: - namespace detail { - struct PluginIntegerTypeStorage; - struct PluginFloatTypeStorage; -+ struct PluginPointerTypeStorage; - } - - class PluginIntegerType : public Type::TypeBase { -@@ -117,6 +118,17 @@ public: - unsigned getWidth() const; - }; - -+class PluginPointerType : public Type::TypeBase { -+public: -+ using Base::Base; -+ -+ PluginTypeID getPluginTypeID (); -+ -+ static PluginPointerType get(MLIRContext *context, Type pointee); -+ -+ Type getElementType(); -+}; // class PluginPointerType -+ - class PluginVoidType : public Type::TypeBase { - public: - using Base::Base; -diff --git a/include/PluginClient/PluginClient.h b/include/PluginClient/PluginClient.h -index b18ecc0..51e16c9 100644 ---- a/include/PluginClient/PluginClient.h -+++ b/include/PluginClient/PluginClient.h -@@ -128,7 +128,7 @@ public: - Json::Value RetOpJsonSerialize(mlir::Plugin::RetOp data, uint64_t&); - Json::Value ValueJsonSerialize(mlir::Value value); - /* 将Type类型数据序列化 */ -- void TypeJsonSerialize(PluginIR::PluginTypeBase& type, string& out); -+ Json::Value TypeJsonSerialize(PluginIR::PluginTypeBase& type); - /* 获取gcc插件数据并进行IR转换,将转换后的数据序列化返回给server。param:函数入参序列化后的数据 */ - void IRTransBegin(const string& funname, const string& param); - /* 从配置文件读取初始化信息 */ -diff --git a/lib/Dialect/PluginDialect.cpp b/lib/Dialect/PluginDialect.cpp -index a53861e..7071e64 100644 ---- a/lib/Dialect/PluginDialect.cpp -+++ b/lib/Dialect/PluginDialect.cpp -@@ -36,6 +36,7 @@ using namespace mlir::Plugin; - void PluginDialect::initialize() { - addTypes(); -diff --git a/lib/Dialect/PluginTypes.cpp b/lib/Dialect/PluginTypes.cpp -index bd5f145..0c0e048 100644 ---- a/lib/Dialect/PluginTypes.cpp -+++ b/lib/Dialect/PluginTypes.cpp -@@ -74,6 +74,25 @@ namespace detail { - - unsigned width : 30; - }; -+ -+ struct PluginPointerTypeStorage : public TypeStorage { -+ using KeyTy = Type; -+ -+ PluginPointerTypeStorage(const KeyTy &key) -+ : pointee(key) {} -+ -+ static PluginPointerTypeStorage *construct(TypeStorageAllocator &allocator, -+ KeyTy key) { -+ return new (allocator.allocate()) -+ PluginPointerTypeStorage(key); -+ } -+ -+ bool operator==(const KeyTy &key) const { -+ return KeyTy(pointee) == key; -+ } -+ -+ Type pointee; -+ }; - } // namespace detail - } // namespace PluginIR - -@@ -96,6 +115,9 @@ PluginTypeID PluginTypeBase::getPluginTypeID () - if (auto Ty = dyn_cast()) { - return Ty.getPluginTypeID (); - } -+ if (auto Ty = dyn_cast()) { -+ return Ty.getPluginTypeID (); -+ } - return PluginTypeID::UndefTyID; - } - -@@ -254,4 +276,23 @@ PluginTypeID PluginVoidType::getPluginTypeID() - PluginTypeID PluginUndefType::getPluginTypeID() - { - return PluginTypeID::UndefTyID; -+} -+ -+//===----------------------------------------------------------------------===// -+// Plugin Pointer Type -+//===----------------------------------------------------------------------===// -+ -+PluginTypeID PluginPointerType::getPluginTypeID() -+{ -+ return PluginTypeID::PointerTyID; -+} -+ -+Type PluginPointerType::getElementType() -+{ -+ return getImpl()->pointee; -+} -+ -+PluginPointerType PluginPointerType::get (MLIRContext *context, Type pointee) -+{ -+ return Base::get(context, pointee); - } -\ No newline at end of file -diff --git a/lib/PluginClient/PluginClient.cpp b/lib/PluginClient/PluginClient.cpp -index e8a7d7d..237eccb 100644 ---- a/lib/PluginClient/PluginClient.cpp -+++ b/lib/PluginClient/PluginClient.cpp -@@ -70,7 +70,7 @@ int PluginClient::GetEvent(InjectPoint inject, plugin_event *event) - return -1; - } - --void PluginClient::TypeJsonSerialize (PluginIR::PluginTypeBase& type, string& out) -+Json::Value PluginClient::TypeJsonSerialize (PluginIR::PluginTypeBase& type) - { - Json::Value root; - Json::Value operationObj; -@@ -82,6 +82,11 @@ void PluginClient::TypeJsonSerialize (PluginIR::PluginTypeBase& type, string& ou - ReTypeId = static_cast(type.getPluginTypeID()); - item["id"] = std::to_string(ReTypeId); - -+ if (auto elemTy = type.dyn_cast()) { -+ auto baseTy = elemTy.getElementType().dyn_cast(); -+ item["elementType"] = TypeJsonSerialize(baseTy); -+ } -+ - if (type.getPluginIntOrFloatBitWidth() != 0) { - ReTypeWidth = type.getPluginIntOrFloatBitWidth(); - item["width"] = std::to_string(ReTypeWidth); -@@ -102,7 +107,7 @@ void PluginClient::TypeJsonSerialize (PluginIR::PluginTypeBase& type, string& ou - } - - root["type"] = item; -- out = root.toStyledString(); -+ return root; - } - - void PluginClient::FunctionOpJsonSerialize(vector& data, string& out) -diff --git a/lib/Translate/TypeTranslation.cpp b/lib/Translate/TypeTranslation.cpp -index 492a895..4c390fa 100644 ---- a/lib/Translate/TypeTranslation.cpp -+++ b/lib/Translate/TypeTranslation.cpp -@@ -95,6 +95,8 @@ private: - return PluginBooleanType::get(&context); - if (TREE_CODE(type) == VOID_TYPE) - return PluginVoidType::get(&context); -+ if (TREE_CODE(type) == POINTER_TYPE) -+ return PluginPointerType::get(&context, translatePrimitiveType(TREE_TYPE(type))); - return PluginUndefType::get(&context); - } - --- -2.27.0.windows.1 - diff --git a/pin-gcc-client-0.3.0.tar.gz b/pin-gcc-client-0.3.0.tar.gz deleted file mode 100644 index 5782dcd3be229bfb67de15246e567e629e3dff9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33917 zcmV(>K-j+@iwFP!000001MFM-b0SBQ_OI^0qJrHBqg_C6jUVTW)gWe!7YPo~%sMVE zh^D)Mwwi9PAJT9e{@?G*%&L9>(s(0g?Yr3NA3UO~Dl03WUuLy8?uXejjOT7RTWQzV z$rqpgIl*&vb;bYU+5H!T7hjxSoL`)soSdDV)4bD*%af}wmj47^_MSY=+yq-Dah$z0 z?_=Y;hx>o>T%IW}UaxhOeSf08tA(re*BA4zUGM5@K0moQJM}KlUY%TBUR}6fzq<5Z zo%`DPy?Orpe7a{7MD3;LwY@Na4YW@>=be+|PrL{D!>d=9&-*|A-u3_Uld~@_KQSK% zpMP=xKdArCGRT5u6es$V>>=_0;(7g_?&<&P?CSK3-$aQ2;`%?H=RxTI>2pl~7k!@f z|8?x=p-w-=9v}1n)60GTzqmaA?Ek;P^Pg!x7gei97(T8W|K)tSakG{BUeQnI%RCA3 z_bSUa>9@znFpO0`?*K9$(=h+1y-DJqwU?3AIA6{aH}dTAI9aw&&pIca)8G4?pP$3e zLI3aGx(|8~q*>a@KD=o4zv}sj|GzrFyxjHwS0|SjpZ)(gc)T@KJzED+u+G=BME`dl zB-(Gj>y0P<;hj3~Ty{>694A;bN5etC`;+S4jtI>kIZDaeO&kW^wmIod?U=gjy+3kv z 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 diff --git a/pin-gcc-client-0.4.0.tar.gz b/pin-gcc-client-0.4.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..745c5069206d8e82ccd9a5a28eecb1a618128880 GIT binary patch literal 52554 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 - 0.4.0-1 +- Type:Update +- ID:NA +- SUG:NA +- DESC:Update to v0.4.0 + * Thu Dec 08 2022 benniaobufeijiushiji - 0.3.0-2 - Type:Sync - ID:NA -- Gitee