From 56a63c2ec2865e0ab99491187c616c02d361368f Mon Sep 17 00:00:00 2001 From: huitailangzju <804544223@qq.com> Date: Tue, 20 Dec 2022 17:13:03 +0800 Subject: [PATCH] [Update] Update to v0.4.0 (cherry picked from commit 180b575cd2f9ba64324288d2ede521430c89237a) --- ...rt-for-new-insertion-points-and-new-.patch | 85 -- 0002-Pin-server-support-LoopOp.patch | 772 -------------- ...rt-build-CFG-CondOp-CallOp-PhiOp-and.patch | 984 ------------------ ...n-server-Support-Plugin-Pointer-Type.patch | 201 ---- pin-server-0.3.0.tar.gz | Bin 20496 -> 0 bytes pin-server-0.4.0.tar.gz | Bin 0 -> 41798 bytes pin-server.spec | 20 +- 7 files changed, 8 insertions(+), 2054 deletions(-) delete mode 100644 0001-Pin-server-Support-for-new-insertion-points-and-new-.patch delete mode 100644 0002-Pin-server-support-LoopOp.patch delete mode 100644 0003-Pin-server-Support-build-CFG-CondOp-CallOp-PhiOp-and.patch delete mode 100644 0004-Pin-server-Support-Plugin-Pointer-Type.patch delete mode 100644 pin-server-0.3.0.tar.gz create mode 100644 pin-server-0.4.0.tar.gz diff --git a/0001-Pin-server-Support-for-new-insertion-points-and-new-.patch b/0001-Pin-server-Support-for-new-insertion-points-and-new-.patch deleted file mode 100644 index 08ffab7..0000000 --- a/0001-Pin-server-Support-for-new-insertion-points-and-new-.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 192ac2d7c8568fa5c8f02039707bc951747c877b Mon Sep 17 00:00:00 2001 -From: dingguangya -Date: Wed, 7 Dec 2022 21:59:02 +0800 -Subject: [PATCH 1/4] [Pin-server] Support for new insertion points and new - Pass It supports the phiopt insertion point and provides a simple - arraywiden pass interface. - ---- - include/PluginServer/PluginServer.h | 1 + - user.cpp | 42 +++++++++++++++++++++++++++-- - 2 files changed, 41 insertions(+), 2 deletions(-) - -diff --git a/include/PluginServer/PluginServer.h b/include/PluginServer/PluginServer.h -index 667cedc..2cb314c 100644 ---- a/include/PluginServer/PluginServer.h -+++ b/include/PluginServer/PluginServer.h -@@ -79,6 +79,7 @@ enum InjectPoint : uint8_t { - // 参考点名称 - enum RefPassName { - PASS_CFG, -+ PASS_PHIOPT, - PASS_SSA, - PASS_LOOP, - }; -diff --git a/user.cpp b/user.cpp -index 50fc3bb..81958c0 100644 ---- a/user.cpp -+++ b/user.cpp -@@ -77,13 +77,51 @@ static void PassManagerSetupFunc(void) - printf("PassManagerSetupFunc in\n"); - } - -+static bool -+determineLoopForm(LoopOp loop) -+{ -+ if (loop.innerLoopIdAttr().getUInt() != 0 || loop.numBlockAttr().getUInt() != 3) -+ { -+ printf ("\nWrong loop form, there is inner loop or redundant bb.\n"); -+ return false; -+ } -+ -+ if (loop.GetSingleExit().first != 0 || !loop.GetLatch()) -+ { -+ printf ("\nWrong loop form, only one exit or loop_latch does not exist.\n"); -+ return false; -+ } -+ return true; -+} -+ -+static void -+ProcessArrayWiden(void) -+{ -+ std::cout << "Running first pass, OMG\n"; -+ -+ PluginServerAPI pluginAPI; -+ vector allFunction = pluginAPI.GetAllFunc(); -+ -+ for (auto &funcOp : allFunction) { -+ string name = funcOp.funcNameAttr().getValue().str(); -+ printf("Now process func : %s \n", name.c_str()); -+ vector allLoop = funcOp.GetAllLoops(); -+ for (auto &loop : allLoop) { -+ if (determineLoopForm(loop)) { -+ printf("The %dth loop form is success matched, and the loop can be optimized.\n", loop.indexAttr().getUInt()); -+ return; -+ } -+ } -+ } -+} -+ - void RegisterCallbacks(void) - { - PluginServer::GetInstance()->RegisterUserFunc(HANDLE_BEFORE_IPA, UserOptimizeFunc); - PluginServer::GetInstance()->RegisterUserFunc(HANDLE_BEFORE_IPA, LocalVarSummery); - ManagerSetupData setupData; -- setupData.refPassName = PASS_CFG; -+ setupData.refPassName = PASS_PHIOPT; - setupData.passNum = 1; - setupData.passPosition = PASS_INSERT_AFTER; -- PluginServer::GetInstance()->RegisterPassManagerSetup(HANDLE_MANAGER_SETUP, setupData, PassManagerSetupFunc); -+ PluginServer::GetInstance()->RegisterPassManagerSetup(HANDLE_MANAGER_SETUP, setupData, ProcessArrayWiden); - } --- -2.27.0.windows.1 - diff --git a/0002-Pin-server-support-LoopOp.patch b/0002-Pin-server-support-LoopOp.patch deleted file mode 100644 index 7e8ffff..0000000 --- a/0002-Pin-server-support-LoopOp.patch +++ /dev/null @@ -1,772 +0,0 @@ -From c51ee872abc92b72fa35f7ff52c2d9e506dde40a Mon Sep 17 00:00:00 2001 -From: benniaobufeijiushiji -Date: Wed, 7 Dec 2022 14:52:19 +0800 -Subject: [PATCH 2/4] [Pin-server] support LoopOp Add LoopOp for Plugin Dialect - ---- - include/Dialect/PluginOps.td | 35 +++++ - include/PluginAPI/BasicPluginOpsAPI.h | 11 ++ - include/PluginAPI/PluginServerAPI.h | 20 +++ - include/PluginServer/PluginServer.h | 21 +++ - lib/Dialect/PluginOps.cpp | 96 ++++++++++++- - lib/PluginAPI/PluginServerAPI.cpp | 171 +++++++++++++++++++++++- - lib/PluginServer/PluginServer.cpp | 185 +++++++++++++++++++++++++- - user.cpp | 16 +-- - 8 files changed, 541 insertions(+), 14 deletions(-) - -diff --git a/include/Dialect/PluginOps.td b/include/Dialect/PluginOps.td -index 374340c..02d9bdd 100644 ---- a/include/Dialect/PluginOps.td -+++ b/include/Dialect/PluginOps.td -@@ -20,6 +20,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"; -@@ -38,6 +39,10 @@ def FunctionOp : Plugin_Op<"function", [NoSideEffect]> { - let builders = [ - OpBuilderDAG<(ins "uint64_t":$id, "StringRef":$funcName, "bool":$declaredInline)> - ]; -+ -+ let extraClassDeclaration = [{ -+ std::vector GetAllLoops(); -+ }]; - } - - def LocalDeclOp : Plugin_Op<"declaration", [NoSideEffect]> { -@@ -54,4 +59,34 @@ 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)> -+ ]; -+ let extraClassDeclaration = [{ -+ uint64_t GetHeader(); -+ uint64_t GetLatch(); -+ std::pair GetSingleExit(); -+ void Delete(); -+ LoopOp GetInnerLoop(); -+ LoopOp GetOuterLoop(); -+ bool IsBlockInside(uint64_t); -+ std::vector > GetExitEdges(); -+ std::vector GetLoopBody(); -+ void AddLoop(uint64_t, uint64_t); -+ }]; -+} -+ - #endif // PLUGIN_OPS_TD -\ No newline at end of file -diff --git a/include/PluginAPI/BasicPluginOpsAPI.h b/include/PluginAPI/BasicPluginOpsAPI.h -index b6f2b4f..fde5f63 100644 ---- a/include/PluginAPI/BasicPluginOpsAPI.h -+++ b/include/PluginAPI/BasicPluginOpsAPI.h -@@ -25,6 +25,7 @@ - namespace PluginAPI { - using std::vector; - using std::string; -+using std::pair; - using namespace mlir::Plugin; - - /* The BasicPluginOpsAPI class defines the basic plugin API, both the plugin -@@ -37,6 +38,16 @@ public: - - virtual vector GetAllFunc() = 0; - virtual vector GetDecls(uint64_t) = 0; -+ virtual LoopOp AllocateNewLoop(uint64_t) = 0; -+ virtual vector GetLoopsFromFunc(uint64_t) = 0; -+ virtual LoopOp GetLoopById(uint64_t) = 0; -+ virtual void AddLoop(uint64_t, uint64_t, uint64_t) = 0; -+ virtual void DeleteLoop(uint64_t) = 0; -+ virtual vector GetLoopBody(uint64_t) = 0; -+ virtual bool IsBlockInLoop(uint64_t, uint64_t) = 0; -+ virtual pair LoopSingleExit(uint64_t) = 0; -+ virtual vector > GetLoopExitEdges(uint64_t) = 0; -+ virtual LoopOp GetBlockLoopFather(uint64_t) = 0; - }; // class BasicPluginOpsAPI - } // namespace PluginAPI - -diff --git a/include/PluginAPI/PluginServerAPI.h b/include/PluginAPI/PluginServerAPI.h -index 7cb4fa7..5b14f2e 100644 ---- a/include/PluginAPI/PluginServerAPI.h -+++ b/include/PluginAPI/PluginServerAPI.h -@@ -29,6 +29,7 @@ namespace PluginAPI { - - using std::vector; - using std::string; -+using std::pair; - using namespace mlir::Plugin; - class PluginServerAPI : public BasicPluginOpsAPI { - public: -@@ -38,9 +39,28 @@ public: - vector GetAllFunc() override; - vector GetDecls(uint64_t) override; - PluginIR::PluginTypeID GetTypeCodeFromString(string type); -+ LoopOp AllocateNewLoop(uint64_t funcID); -+ LoopOp GetLoopById(uint64_t loopID); -+ vector GetLoopsFromFunc(uint64_t funcID); -+ bool IsBlockInLoop(uint64_t loopID, uint64_t blockID); -+ void DeleteLoop(uint64_t loopID); -+ void AddLoop(uint64_t loopID, uint64_t outerID, uint64_t funcID); -+ pair LoopSingleExit(uint64_t loopID); -+ vector > GetLoopExitEdges(uint64_t loopID); -+ uint64_t GetHeader(uint64_t loopID); -+ uint64_t GetLatch(uint64_t loopID); -+ vector GetLoopBody(uint64_t loopID); -+ LoopOp GetBlockLoopFather(uint64_t blockID); - private: - vector GetOperationResult(const string& funName, const string& params); - vector GetDeclOperationResult(const string& funName, const string& params); -+ LoopOp GetLoopResult(const string&funName, const string& params); -+ vector GetLoopsResult(const string& funName, const string& params); -+ bool GetBoolResult(const string& funName, const string& params); -+ pair EdgeResult(const string& funName, const string& params); -+ vector > EdgesResult(const string& funName, const string& params); -+ uint64_t BlockResult(const string& funName, const string& params); -+ vector BlocksResult(const string& funName, const string& params); - void WaitClientResult(const string& funName, const string& params); - }; // class PluginServerAPI - } // namespace PluginAPI -diff --git a/include/PluginServer/PluginServer.h b/include/PluginServer/PluginServer.h -index 2cb314c..610ecb9 100644 ---- a/include/PluginServer/PluginServer.h -+++ b/include/PluginServer/PluginServer.h -@@ -130,6 +130,13 @@ public: - static PluginServer *GetInstance(void); - vector GetFunctionOpResult(void); - vector GetLocalDeclResult(void); -+ mlir::Plugin::LoopOp LoopOpResult(void); -+ vector LoopOpsResult(void); -+ vector BlockIdsResult(void); -+ uint64_t BlockIdResult(void); -+ vector > EdgesResult(void); -+ std::pair EdgeResult(void); -+ bool BoolResult(void); - /* 回调函数接口,用于向server注册用户需要执行的函数 */ - int RegisterUserFunc(InjectPoint inject, UserFunc func); - int RegisterPassManagerSetup(InjectPoint inject, const ManagerSetupData& passData, UserFunc func); -@@ -176,6 +183,13 @@ public: - void FuncOpJsonDeSerialize(const string& data); - void TypeJsonDeSerialize(const string& data); - void LocalDeclOpJsonDeSerialize(const string& data); -+ void LoopOpsJsonDeSerialize(const string& data); -+ void LoopOpJsonDeSerialize(const string& data); -+ void BoolResJsonDeSerialize(const string& data); -+ void EdgesJsonDeSerialize(const string& data); -+ void EdgeJsonDeSerialize(const string& data); -+ void BlocksJsonDeSerialize(const string& data); -+ void BlockJsonDeSerialize(const string& data); - /* json反序列化,根据key值分别调用Operation/Decl/Type反序列化接口函数 */ - void JsonDeSerialize(const string& key, const string& data); - /* 解析客户端发送过来的-fplugin-arg参数,并保存在私有变量args中 */ -@@ -223,6 +237,13 @@ private: - vector funcOpData; - PluginIR::PluginTypeBase pluginType; - vector decls; -+ vector loops; -+ mlir::Plugin::LoopOp loop; -+ vector > edges; -+ std::pair edge; -+ vector blockIds; -+ uint64_t blockId; -+ bool boolRes; - /* 保存用户注册的回调函数,它们将在注入点事件触发后调用 */ - map> userFunc; - string apiFuncName; // 保存用户调用PluginAPI的函数名 -diff --git a/lib/Dialect/PluginOps.cpp b/lib/Dialect/PluginOps.cpp -index 2377875..481d51a 100644 ---- a/lib/Dialect/PluginOps.cpp -+++ b/lib/Dialect/PluginOps.cpp -@@ -20,6 +20,7 @@ - // - //===----------------------------------------------------------------------===// - -+#include "PluginAPI/PluginServerAPI.h" - #include "Dialect/PluginDialect.h" - #include "Dialect/PluginOps.h" - -@@ -29,15 +30,24 @@ - - using namespace mlir; - using namespace mlir::Plugin; -+using std::vector; -+using std::pair; - - 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)); - } - -+vector FunctionOp::GetAllLoops() -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t funcId = idAttr().getInt(); -+ return pluginAPI.GetLoopsFromFunc(funcId); -+} -+ - void LocalDeclOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, - uint64_t id, StringRef symName, - int64_t typeID, uint64_t typeWidth) { -@@ -48,6 +58,90 @@ 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)); -+} -+ -+// FIXME: use Block instead of uint64_t -+uint64_t LoopOp::GetHeader() -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t loopId = idAttr().getInt(); -+ return pluginAPI.GetHeader(loopId); -+} -+ -+// FIXME: use Block instead of uint64_t -+uint64_t LoopOp::GetLatch() -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t loopId = idAttr().getInt(); -+ return pluginAPI.GetLatch(loopId); -+} -+ -+vector LoopOp::GetLoopBody() -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t loopId = idAttr().getInt(); -+ return pluginAPI.GetLoopBody(loopId); -+} -+ -+pair LoopOp::GetSingleExit() -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t loopId = idAttr().getInt(); -+ return pluginAPI.LoopSingleExit(loopId); -+} -+ -+void LoopOp::Delete() -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t loopId = idAttr().getInt(); -+ pluginAPI.DeleteLoop(loopId); -+} -+ -+LoopOp LoopOp::GetInnerLoop() -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t loopId = innerLoopIdAttr().getInt(); -+ return pluginAPI.GetLoopById(loopId); -+} -+ -+LoopOp LoopOp::GetOuterLoop() -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t loopId = outerLoopIdAttr().getInt(); -+ return pluginAPI.GetLoopById(loopId); -+} -+ -+// FIXME: 用Block替换uint64_t -+bool LoopOp::IsBlockInside(uint64_t b) -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t loopId = idAttr().getInt(); -+ return pluginAPI.IsBlockInLoop(loopId, b); -+} -+ -+vector > LoopOp::GetExitEdges() -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t loopId = idAttr().getInt(); -+ return pluginAPI.GetLoopExitEdges(loopId); -+} -+ -+void LoopOp::AddLoop(uint64_t outerId, uint64_t funcId) -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ uint64_t loopId = idAttr().getInt(); -+ return pluginAPI.AddLoop(loopId, outerId, funcId); -+} -+ - //===----------------------------------------------------------------------===// - // TableGen'd op method definitions - //===----------------------------------------------------------------------===// -diff --git a/lib/PluginAPI/PluginServerAPI.cpp b/lib/PluginAPI/PluginServerAPI.cpp -index b6ed53f..41626f9 100644 ---- a/lib/PluginAPI/PluginServerAPI.cpp -+++ b/lib/PluginAPI/PluginServerAPI.cpp -@@ -116,10 +116,179 @@ vector PluginServerAPI::GetDecls(uint64_t funcID) - { - Json::Value root; - string funName("GetLocalDecls"); -- root[std::to_string(0)] = std::to_string(funcID); -+ root["funcId"] = std::to_string(funcID); - string params = root.toStyledString(); - - return GetDeclOperationResult(funName, params); - } - -+vector PluginServerAPI::GetLoopsResult(const string& funName, const string& params) -+{ -+ WaitClientResult(funName, params); -+ vector loops = PluginServer::GetInstance()->LoopOpsResult(); -+ return loops; -+} -+ -+LoopOp PluginServerAPI::GetLoopResult(const string& funName, const string& params) -+{ -+ WaitClientResult(funName, params); -+ LoopOp loop = PluginServer::GetInstance()->LoopOpResult(); -+ return loop; -+} -+ -+bool PluginServerAPI::GetBoolResult(const string& funName, const string& params) -+{ -+ WaitClientResult(funName, params); -+ return PluginServer::GetInstance()->BoolResult(); -+} -+ -+pair PluginServerAPI::EdgeResult(const string& funName, const string& params) -+{ -+ WaitClientResult(funName, params); -+ pair e = PluginServer::GetInstance()->EdgeResult(); -+ return e; -+} -+ -+vector > PluginServerAPI::EdgesResult(const string& funName, const string& params) -+{ -+ WaitClientResult(funName, params); -+ vector > retEdges = PluginServer::GetInstance()->EdgesResult(); -+ return retEdges; -+} -+ -+uint64_t PluginServerAPI::BlockResult(const string& funName, const string& params) -+{ -+ WaitClientResult(funName, params); -+ return PluginServer::GetInstance()->BlockIdResult(); -+} -+ -+vector PluginServerAPI::BlocksResult(const string& funName, const string& params) -+{ -+ WaitClientResult(funName, params); -+ vector retBlocks = PluginServer::GetInstance()->BlockIdsResult(); -+ return retBlocks; -+} -+ -+vector PluginServerAPI::GetLoopsFromFunc(uint64_t funcID) -+{ -+ Json::Value root; -+ string funName("GetLoopsFromFunc"); -+ root["funcId"] = std::to_string(funcID); -+ string params = root.toStyledString(); -+ -+ return GetLoopsResult(funName, params); -+} -+ -+// FIXME: 入参void -+LoopOp PluginServerAPI::AllocateNewLoop(uint64_t funcID) -+{ -+ Json::Value root; -+ string funName("AllocateNewLoop"); -+ root["funcId"] = std::to_string(funcID); -+ string params = root.toStyledString(); -+ -+ return GetLoopResult(funName, params); -+} -+ -+LoopOp PluginServerAPI::GetLoopById(uint64_t loopID) -+{ -+ Json::Value root; -+ string funName("GetLoopById"); -+ root["loopId"] = std::to_string(loopID); -+ string params = root.toStyledString(); -+ -+ return GetLoopResult(funName, params); -+} -+ -+void PluginServerAPI::DeleteLoop(uint64_t loopID) -+{ -+ Json::Value root; -+ string funName("DeleteLoop"); -+ root["loopId"] = std::to_string(loopID); -+ string params = root.toStyledString(); -+ WaitClientResult(funName, params); -+} -+ -+void PluginServerAPI::AddLoop(uint64_t loopID, uint64_t outerID, uint64_t funcID) -+{ -+ Json::Value root; -+ string funName("AddLoop"); -+ root["loopId"] = loopID; -+ root["outerId"] = outerID; -+ root["funcId"] = funcID; -+ string params = root.toStyledString(); -+ WaitClientResult(funName, params); -+} -+ -+bool PluginServerAPI::IsBlockInLoop(uint64_t loopID, uint64_t blockID) -+{ -+ Json::Value root; -+ string funName("IsBlockInside"); -+ root["loopId"] = std::to_string(loopID); -+ root["blockId"] = std::to_string(blockID); -+ string params = root.toStyledString(); -+ -+ return GetBoolResult(funName, params); -+} -+ -+uint64_t PluginServerAPI::GetHeader(uint64_t loopID) -+{ -+ Json::Value root; -+ string funName("GetHeader"); -+ root["loopId"] = std::to_string(loopID); -+ string params = root.toStyledString(); -+ -+ return BlockResult(funName, params); -+} -+ -+uint64_t PluginServerAPI::GetLatch(uint64_t loopID) -+{ -+ Json::Value root; -+ string funName("GetLatch"); -+ root["loopId"] = std::to_string(loopID); -+ string params = root.toStyledString(); -+ -+ return BlockResult(funName, params); -+} -+ -+pair PluginServerAPI::LoopSingleExit(uint64_t loopID) -+{ -+ Json::Value root; -+ string funName("GetLoopSingleExit"); -+ root["loopId"] = std::to_string(loopID); -+ string params = root.toStyledString(); -+ -+ return EdgeResult(funName, params); -+} -+ -+vector > PluginServerAPI::GetLoopExitEdges(uint64_t loopID) -+{ -+ Json::Value root; -+ string funName("GetExitEdges"); -+ root["loopId"] = std::to_string(loopID); -+ string params = root.toStyledString(); -+ -+ return EdgesResult(funName, params); -+} -+ -+vector PluginServerAPI::GetLoopBody(uint64_t loopID) -+{ -+ Json::Value root; -+ string funName("GetBlocksInLoop"); -+ root["loopId"] = std::to_string(loopID); -+ string params = root.toStyledString(); -+ -+ return BlocksResult(funName, params); -+} -+ -+LoopOp PluginServerAPI::GetBlockLoopFather(uint64_t blockID) -+{ -+ Json::Value root; -+ string funName("GetBlockLoopFather"); -+ root["blockId"] = std::to_string(blockID); -+ string params = root.toStyledString(); -+ -+ return GetLoopResult(funName, params); -+} -+ - } // namespace Plugin_IR -diff --git a/lib/PluginServer/PluginServer.cpp b/lib/PluginServer/PluginServer.cpp -index 1ec47ae..92159e8 100644 ---- a/lib/PluginServer/PluginServer.cpp -+++ b/lib/PluginServer/PluginServer.cpp -@@ -40,6 +40,7 @@ using namespace mlir::Plugin; - - using std::cout; - using std::endl; -+using std::pair; - static std::unique_ptr g_server; // grpc对象指针 - static PluginServer g_service; // 插件server对象 - -@@ -88,6 +89,52 @@ vector PluginServer::GetLocalDeclResult() - return retOps; - } - -+vector PluginServer::LoopOpsResult() -+{ -+ vector retLoops = loops; -+ loops.clear(); -+ return retLoops; -+} -+ -+LoopOp PluginServer::LoopOpResult() -+{ -+ mlir::Plugin::LoopOp retLoop = loop; -+ return retLoop; -+} -+ -+bool PluginServer::BoolResult() -+{ -+ return boolRes; -+} -+ -+uint64_t PluginServer::BlockIdResult() -+{ -+ return blockId; -+} -+ -+vector PluginServer::BlockIdsResult() -+{ -+ vector retIds = blockIds; -+ blockIds.clear(); -+ return retIds; -+} -+ -+pair PluginServer::EdgeResult() -+{ -+ pair e; -+ e.first = edge.first; -+ e.second = edge.second; -+ return e; -+} -+ -+vector > PluginServer::EdgesResult() -+{ -+ vector > retEdges; -+ retEdges = edges; -+ edges.clear(); -+ return retEdges; -+} -+ - void PluginServer::JsonGetAttributes(Json::Value node, map& attributes) - { - Json::Value::Members attMember = node.getMemberNames(); -@@ -110,7 +157,23 @@ void PluginServer::JsonDeSerialize(const string& key, const string& data) - FuncOpJsonDeSerialize(data); - } else if (key == "LocalDeclOpResult") { - LocalDeclOpJsonDeSerialize(data); -- }else { -+ } else if (key == "LoopOpResult") { -+ LoopOpJsonDeSerialize (data); -+ } else if (key == "LoopOpsResult") { -+ LoopOpsJsonDeSerialize (data); -+ } else if (key == "BoolResult") { -+ BoolResJsonDeSerialize(data); -+ } else if (key == "VoidResult") { -+ ; -+ } else if (key == "BlockIdResult") { -+ BlockJsonDeSerialize(data); -+ } else if (key == "EdgeResult") { -+ EdgeJsonDeSerialize(data); -+ } else if (key == "EdgesResult") { -+ EdgesJsonDeSerialize(data); -+ } else if (key == "BlockIdsResult") { -+ BlocksJsonDeSerialize(data); -+ } else { - cout << "not Json,key:" << key << ",value:" << data << endl; - } - } -@@ -198,14 +261,128 @@ void PluginServer::LocalDeclOpJsonDeSerialize(const string& data) - Json::Value attributes = node["attributes"]; - map declAttributes; - JsonGetAttributes(attributes, declAttributes); -- string symName = declAttributes["symName"]; -- uint64_t typeID = atol(declAttributes["typeID"].c_str()); -- uint64_t typeWidth = atol(declAttributes["typeWidth"].c_str()); -+ string symName = declAttributes["symName"]; -+ uint64_t typeID = atol(declAttributes["typeID"].c_str()); -+ uint64_t typeWidth = atol(declAttributes["typeWidth"].c_str()); - auto location = builder.getUnknownLoc(); - LocalDeclOp op = builder.create(location, id, symName, typeID, typeWidth); - decls.push_back(op); - } - } -+void PluginServer::LoopOpsJsonDeSerialize(const string& data) -+{ -+ Json::Value root; -+ Json::Reader reader; -+ Json::Value node; -+ reader.parse(data, root); -+ -+ Json::Value::Members operation = root.getMemberNames(); -+ context.getOrLoadDialect(); -+ mlir::OpBuilder builder(&context); -+ for (Json::Value::Members::iterator iter = operation.begin(); iter != operation.end(); iter++) { -+ string operationKey = *iter; -+ node = root[operationKey]; -+ int64_t id = GetID(node["id"]); -+ Json::Value attributes = node["attributes"]; -+ map loopAttributes; -+ JsonGetAttributes(attributes, loopAttributes); -+ uint32_t index = atoi(attributes["index"].asString().c_str()); -+ uint64_t innerId = atol(loopAttributes["innerLoopId"].c_str()); -+ uint64_t outerId = atol(loopAttributes["outerLoopId"].c_str()); -+ uint32_t numBlock = atoi(loopAttributes["numBlock"].c_str()); -+ auto location = builder.getUnknownLoc(); -+ LoopOp op = builder.create(location, id, index, innerId, outerId, numBlock); -+ loops.push_back(op); -+ } -+} -+ -+void PluginServer::LoopOpJsonDeSerialize(const string& data) -+{ -+ Json::Value root; -+ Json::Reader reader; -+ reader.parse(data, root); -+ -+ context.getOrLoadDialect(); -+ mlir::OpBuilder builder(&context); -+ -+ uint64_t id = GetID(root["id"]); -+ Json::Value attributes = root["attributes"]; -+ uint32_t index = atoi(attributes["index"].asString().c_str()); -+ uint64_t innerLoopId = atol(attributes["innerLoopId"].asString().c_str()); -+ uint64_t outerLoopId = atol(attributes["outerLoopId"].asString().c_str()); -+ uint32_t numBlock = atoi(attributes["numBlock"].asString().c_str()); -+ auto location = builder.getUnknownLoc(); -+ loop = builder.create(location, id, index, innerLoopId, outerLoopId, numBlock); -+} -+ -+void PluginServer::BoolResJsonDeSerialize(const string& data) -+{ -+ Json::Value root; -+ Json::Reader reader; -+ reader.parse(data, root); -+ -+ boolRes = (bool)atoi(root["result"].asString().c_str()); -+} -+ -+void PluginServer::EdgesJsonDeSerialize(const string& data) -+{ -+ Json::Value root; -+ Json::Reader reader; -+ Json::Value node; -+ reader.parse(data, root); -+ -+ Json::Value::Members operation = root.getMemberNames(); -+ context.getOrLoadDialect(); -+ mlir::OpBuilder builder(&context); -+ for (Json::Value::Members::iterator iter = operation.begin(); iter != operation.end(); iter++) { -+ string operationKey = *iter; -+ node = root[operationKey]; -+ uint64_t src = atol(node["src"].asString().c_str()); -+ uint64_t dest = atol(node["dest"].asString().c_str()); -+ pair e; -+ e.first = src; -+ e.second = dest; -+ edges.push_back(e); -+ } -+} -+ -+void PluginServer::EdgeJsonDeSerialize(const string& data) -+{ -+ Json::Value root; -+ Json::Reader reader; -+ reader.parse(data, root); -+ uint64_t src = atol(root["src"].asString().c_str()); -+ uint64_t dest = atol(root["dest"].asString().c_str()); -+ edge.first = src; -+ edge.second = dest; -+} -+ -+void PluginServer::BlocksJsonDeSerialize(const string& data) -+{ -+ Json::Value root; -+ Json::Reader reader; -+ Json::Value node; -+ reader.parse(data, root); -+ -+ Json::Value::Members operation = root.getMemberNames(); -+ context.getOrLoadDialect(); -+ mlir::OpBuilder builder(&context); -+ for (Json::Value::Members::iterator iter = operation.begin(); iter != operation.end(); iter++) { -+ string operationKey = *iter; -+ node = root[operationKey]; -+ uint64_t id = atol(node["id"].asString().c_str()); -+ blockIds.push_back(id); -+ } -+} -+ -+void PluginServer::BlockJsonDeSerialize(const string& data) -+{ -+ Json::Value root; -+ Json::Reader reader; -+ reader.parse(data, root); -+ -+ blockId = (uint64_t)atol(root["id"].asString().c_str()); -+} - - /* 线程函数,执行用户注册函数,客户端返回数据后退出 */ - static void ExecCallbacks(const string& name) -diff --git a/user.cpp b/user.cpp -index 81958c0..efc4158 100644 ---- a/user.cpp -+++ b/user.cpp -@@ -80,7 +80,7 @@ static void PassManagerSetupFunc(void) - static bool - determineLoopForm(LoopOp loop) - { -- if (loop.innerLoopIdAttr().getUInt() != 0 || loop.numBlockAttr().getUInt() != 3) -+ if (loop.innerLoopIdAttr().getInt() != 0 || loop.numBlockAttr().getInt() != 3) - { - printf ("\nWrong loop form, there is inner loop or redundant bb.\n"); - return false; -@@ -97,21 +97,21 @@ determineLoopForm(LoopOp loop) - static void - ProcessArrayWiden(void) - { -- std::cout << "Running first pass, OMG\n"; -+ std::cout << "Running first pass, awiden\n"; - - PluginServerAPI pluginAPI; - vector allFunction = pluginAPI.GetAllFunc(); -- -+ - for (auto &funcOp : allFunction) { - string name = funcOp.funcNameAttr().getValue().str(); - printf("Now process func : %s \n", name.c_str()); - vector allLoop = funcOp.GetAllLoops(); -- for (auto &loop : allLoop) { -- if (determineLoopForm(loop)) { -- printf("The %dth loop form is success matched, and the loop can be optimized.\n", loop.indexAttr().getUInt()); -- return; -- } -+ for (auto &loop : allLoop) { -+ if (determineLoopForm(loop)) { -+ printf("The %ldth loop form is success matched, and the loop can be optimized.\n", loop.indexAttr().getInt()); -+ return; - } -+ } - } - } - --- -2.27.0.windows.1 - diff --git a/0003-Pin-server-Support-build-CFG-CondOp-CallOp-PhiOp-and.patch b/0003-Pin-server-Support-build-CFG-CondOp-CallOp-PhiOp-and.patch deleted file mode 100644 index 21ac0e7..0000000 --- a/0003-Pin-server-Support-build-CFG-CondOp-CallOp-PhiOp-and.patch +++ /dev/null @@ -1,984 +0,0 @@ -From b721e3a4292503115329d6380b590b3bab1cd856 Mon Sep 17 00:00:00 2001 -From: Mingchuan Wu -Date: Thu, 8 Dec 2022 20:14:09 +0800 -Subject: [PATCH 3/4] [Pin-server] Support build CFG, CondOp, CallOp, PhiOp and - AssignOp. Add CondOp, CallOp, PhiOp and AssignOp for PluginDialect. Now we - can support CFG. - ---- - include/Dialect/CMakeLists.txt | 3 + - include/Dialect/PluginDialect.td | 38 ++++ - include/Dialect/PluginOps.h | 4 + - include/Dialect/PluginOps.td | 142 ++++++++++++++- - include/PluginAPI/BasicPluginOpsAPI.h | 5 + - include/PluginAPI/PluginServerAPI.h | 10 +- - include/PluginServer/PluginServer.h | 22 +++ - lib/Dialect/PluginOps.cpp | 150 +++++++++++++++- - lib/PluginAPI/PluginServerAPI.cpp | 60 ++++++- - lib/PluginServer/PluginServer.cpp | 250 ++++++++++++++++++++++++-- - user.cpp | 2 +- - 11 files changed, 663 insertions(+), 23 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 362a5c8..31b338d 100644 ---- a/include/Dialect/PluginDialect.td -+++ b/include/Dialect/PluginDialect.td -@@ -46,4 +46,42 @@ 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 IDefineCodeUNDEF : I32EnumAttrCase<"UNDEF", 2>; -+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 be2a3ef..8bab877 100644 ---- a/include/Dialect/PluginOps.h -+++ b/include/Dialect/PluginOps.h -@@ -27,6 +27,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 02d9bdd..e91cd84 100644 ---- a/include/Dialect/PluginOps.td -+++ b/include/Dialect/PluginOps.td -@@ -28,8 +28,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); - -@@ -89,4 +89,142 @@ 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 extraClassDeclaration = [{ -+ bool SetLHS(Value lhs); -+ }]; -+ 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)> -+ ]; -+ let extraClassDeclaration = [{ -+ Value GetResult(); -+ Value GetArgDef(int i) { return getOperand(i); } -+ }]; -+} -+ -+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)> -+ ]; -+ let extraClassDeclaration = [{ -+ Value GetLHS() { return getOperand(0); } -+ Value GetRHS1() { return getOperand(1); } -+ Value GetRHS2() { return getOperand(2); } -+ }]; -+} -+ -+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)>, -+ // Only for server. -+ OpBuilderDAG<(ins "IComparisonCode":$condCode, -+ "Value":$lhs, "Value":$rhs)> -+ ]; -+ 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/PluginAPI/BasicPluginOpsAPI.h b/include/PluginAPI/BasicPluginOpsAPI.h -index fde5f63..6f5fbb0 100644 ---- a/include/PluginAPI/BasicPluginOpsAPI.h -+++ b/include/PluginAPI/BasicPluginOpsAPI.h -@@ -48,6 +48,11 @@ public: - virtual pair LoopSingleExit(uint64_t) = 0; - virtual vector > GetLoopExitEdges(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/PluginServerAPI.h b/include/PluginAPI/PluginServerAPI.h -index 5b14f2e..425b946 100644 ---- a/include/PluginAPI/PluginServerAPI.h -+++ b/include/PluginAPI/PluginServerAPI.h -@@ -38,6 +38,8 @@ public: - - vector GetAllFunc() override; - vector GetDecls(uint64_t) override; -+ PhiOp GetPhiOp(uint64_t) override; -+ CallOp GetCallOp(uint64_t) override; - PluginIR::PluginTypeID GetTypeCodeFromString(string type); - LoopOp AllocateNewLoop(uint64_t funcID); - LoopOp GetLoopById(uint64_t loopID); -@@ -51,8 +53,14 @@ public: - uint64_t GetLatch(uint64_t loopID); - vector GetLoopBody(uint64_t loopID); - LoopOp GetBlockLoopFather(uint64_t blockID); -+ /* Plugin API for CallOp. */ -+ bool SetLhsInCallOp(uint64_t, uint64_t); -+ /* Plugin API for CondOp. */ -+ uint64_t CreateCondOp(IComparisonCode, uint64_t, uint64_t) override; -+ mlir::Value GetResultFromPhi(uint64_t) override; -+ - private: -- vector GetOperationResult(const string& funName, const string& params); -+ vector GetFunctionOpResult(const string& funName, const string& params); - vector GetDeclOperationResult(const string& funName, const string& params); - LoopOp GetLoopResult(const string&funName, const string& params); - vector GetLoopsResult(const string& funName, const string& params); -diff --git a/include/PluginServer/PluginServer.h b/include/PluginServer/PluginServer.h -index 610ecb9..b28c6d0 100644 ---- a/include/PluginServer/PluginServer.h -+++ b/include/PluginServer/PluginServer.h -@@ -33,6 +33,7 @@ - #include "Dialect/PluginOps.h" - #include "plugin.grpc.pb.h" - #include "mlir/IR/MLIRContext.h" -+#include "mlir/IR/Builders.h" - #include "Dialect/PluginTypes.h" - - namespace PinServer { -@@ -120,6 +121,7 @@ private: - - class PluginServer final : public PluginService::Service { - public: -+ PluginServer() : opBuilder(&context){} - /* 定义的grpc服务端和客户端通信的接口函数 */ - Status ReceiveSendMsg(ServerContext* context, ServerReaderWriter* stream) override; - /* 服务端发送数据给client接口 */ -@@ -137,6 +139,10 @@ public: - vector > EdgesResult(void); - std::pair EdgeResult(void); - bool BoolResult(void); -+ vector GetOpResult(void); -+ bool GetBoolResult(void); -+ uint64_t GetIdResult(void); -+ mlir::Value GetValueResult(void); - /* 回调函数接口,用于向server注册用户需要执行的函数 */ - int RegisterUserFunc(InjectPoint inject, UserFunc func); - int RegisterPassManagerSetup(InjectPoint inject, const ManagerSetupData& passData, UserFunc func); -@@ -190,6 +196,13 @@ public: - void EdgeJsonDeSerialize(const string& data); - void BlocksJsonDeSerialize(const string& data); - void BlockJsonDeSerialize(const string& data); -+ void CallOpJsonDeSerialize(const string& data); -+ void CondOpJsonDeSerialize(const string& data); -+ void RetOpJsonDeSerialize(const string& data); -+ void FallThroughOpJsonDeSerialize(const string& data); -+ void PhiOpJsonDeSerialize(const string& data); -+ void AssignOpJsonDeSerialize(const string& data); -+ mlir::Value ValueJsonDeSerialize(Json::Value valueJson); - /* json反序列化,根据key值分别调用Operation/Decl/Type反序列化接口函数 */ - void JsonDeSerialize(const string& key, const string& data); - /* 解析客户端发送过来的-fplugin-arg参数,并保存在私有变量args中 */ -@@ -234,6 +247,7 @@ private: - /* 用户函数执行状态,client返回结果后为STATE_RETURN,开始执行下一个函数 */ - volatile UserFunStateEnum userFunState; - mlir::MLIRContext context; -+ mlir::OpBuilder opBuilder; - vector funcOpData; - PluginIR::PluginTypeBase pluginType; - vector decls; -@@ -244,6 +258,10 @@ private: - vector blockIds; - uint64_t blockId; - bool boolRes; -+ vector opData; -+ bool boolResult; -+ bool idResult; -+ mlir::Value valueResult; - /* 保存用户注册的回调函数,它们将在注入点事件触发后调用 */ - map> userFunc; - string apiFuncName; // 保存用户调用PluginAPI的函数名 -@@ -252,6 +270,10 @@ private: - timer_t timerId; - map args; // 保存gcc编译时用户传入参数 - sem_t sem[2]; -+ -+ // process Block. -+ std::map blockMaps; -+ bool ProcessBlock(mlir::Block*, mlir::Region&, const Json::Value&); - }; // class PluginServer - - void RunServer(int timeout, string& port); -diff --git a/lib/Dialect/PluginOps.cpp b/lib/Dialect/PluginOps.cpp -index 481d51a..d647fc4 100644 ---- a/lib/Dialect/PluginOps.cpp -+++ b/lib/Dialect/PluginOps.cpp -@@ -33,8 +33,9 @@ using namespace mlir::Plugin; - using std::vector; - using std::pair; - --void FunctionOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, -- uint64_t id, StringRef funcName, bool declaredInline) { -+void FunctionOp::build(OpBuilder &builder, OperationState &state, -+ uint64_t id, StringRef funcName, bool declaredInline) -+{ - FunctionOp::build(builder, state, - builder.getI64IntegerAttr(id), - builder.getStringAttr(funcName), -@@ -48,9 +49,10 @@ vector FunctionOp::GetAllLoops() - return pluginAPI.GetLoopsFromFunc(funcId); - } - --void LocalDeclOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, -+void LocalDeclOp::build(OpBuilder &builder, OperationState &state, - uint64_t id, StringRef symName, -- int64_t typeID, uint64_t typeWidth) { -+ int64_t typeID, uint64_t typeWidth) -+{ - LocalDeclOp::build(builder, state, - builder.getI64IntegerAttr(id), - builder.getStringAttr(symName), -@@ -142,6 +144,146 @@ void LoopOp::AddLoop(uint64_t outerId, uint64_t funcId) - return pluginAPI.AddLoop(loopId, outerId, funcId); - } - -+//===----------------------------------------------------------------------===// -+// 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(OpBuilder &builder, 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(); } -+ -+bool CallOp::SetLHS(Value lhs) -+{ -+ PlaceholderOp phOp = lhs.getDefiningOp(); -+ uint64_t lhsId = phOp.idAttr().getInt(); -+ PluginAPI::PluginServerAPI pluginAPI; -+ return pluginAPI.SetLhsInCallOp(this->idAttr().getInt(), lhsId); -+} -+ -+//===----------------------------------------------------------------------===// -+// 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.addAttribute("tbaddr", builder.getI64IntegerAttr(tbaddr)); -+ state.addAttribute("fbaddr", builder.getI64IntegerAttr(fbaddr)); -+ state.addOperands({lhs, rhs}); -+ 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); -+} -+ -+void CondOp::build(OpBuilder &builder, OperationState &state, -+ IComparisonCode condCode, Value lhs, Value rhs) -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ PlaceholderOp lhsOp = lhs.getDefiningOp(); -+ uint64_t lhsId = lhsOp.idAttr().getInt(); -+ PlaceholderOp rhsOp = rhs.getDefiningOp(); -+ uint64_t rhsId = rhsOp.idAttr().getInt(); -+ uint64_t id = pluginAPI.CreateCondOp(condCode, lhsId, rhsId); -+ state.addAttribute("id", builder.getI64IntegerAttr(id)); -+ state.addOperands({lhs, rhs}); -+ state.addAttribute("condCode", -+ builder.getI32IntegerAttr(static_cast(condCode))); -+} -+ -+//===----------------------------------------------------------------------===// -+// 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); -+} -+ -+Value PhiOp::GetResult() -+{ -+ PluginAPI::PluginServerAPI pluginAPI; -+ return pluginAPI.GetResultFromPhi(this->idAttr().getInt()); -+} -+ -+//===----------------------------------------------------------------------===// -+// 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); -+} -+ -+//===----------------------------------------------------------------------===// -+// 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/PluginServerAPI.cpp b/lib/PluginAPI/PluginServerAPI.cpp -index 41626f9..65eafa7 100644 ---- a/lib/PluginAPI/PluginServerAPI.cpp -+++ b/lib/PluginAPI/PluginServerAPI.cpp -@@ -54,7 +54,7 @@ void PluginServerAPI::WaitClientResult(const string& funName, const string& para - } - } - --vector PluginServerAPI::GetOperationResult(const string& funName, const string& params) -+vector PluginServerAPI::GetFunctionOpResult(const string& funName, const string& params) - { - WaitClientResult(funName, params); - vector retOps = PluginServer::GetInstance()->GetFunctionOpResult(); -@@ -67,7 +67,63 @@ vector PluginServerAPI::GetAllFunc() - string funName = __func__; - string params = root.toStyledString(); - -- return GetOperationResult(funName, params); -+ return GetFunctionOpResult(funName, params); -+} -+ -+PhiOp PluginServerAPI::GetPhiOp(uint64_t id) -+{ -+ Json::Value root; -+ string funName = __func__; -+ root["id"] = std::to_string(id); -+ string params = root.toStyledString(); -+ WaitClientResult(funName, params); -+ vector opRet = PluginServer::GetInstance()->GetOpResult(); -+ return llvm::dyn_cast(opRet[0]); -+} -+ -+CallOp PluginServerAPI::GetCallOp(uint64_t id) -+{ -+ Json::Value root; -+ string funName = __func__; -+ root["id"] = std::to_string(id); -+ string params = root.toStyledString(); -+ WaitClientResult(funName, params); -+ vector opRet = PluginServer::GetInstance()->GetOpResult(); -+ return llvm::dyn_cast(opRet[0]); -+} -+ -+bool PluginServerAPI::SetLhsInCallOp(uint64_t callId, uint64_t lhsId) -+{ -+ Json::Value root; -+ string funName = __func__; -+ root["callId"] = std::to_string(callId); -+ root["lhsId"] = std::to_string(lhsId); -+ string params = root.toStyledString(); -+ WaitClientResult(funName, params); -+ return PluginServer::GetInstance()->GetBoolResult(); -+} -+ -+uint64_t PluginServerAPI::CreateCondOp(IComparisonCode iCode, -+ uint64_t lhs, uint64_t rhs) -+{ -+ Json::Value root; -+ string funName = __func__; -+ root["condCode"] = std::to_string(static_cast(iCode)); -+ root["lhsId"] = std::to_string(lhs); -+ root["rhsId"] = std::to_string(rhs); -+ string params = root.toStyledString(); -+ WaitClientResult(funName, params); -+ return PluginServer::GetInstance()->GetIdResult(); -+} -+ -+mlir::Value PluginServerAPI::GetResultFromPhi(uint64_t phiId) -+{ -+ Json::Value root; -+ string funName = __func__; -+ root["id"] = std::to_string(phiId); -+ string params = root.toStyledString(); -+ WaitClientResult(funName, params); -+ return PluginServer::GetInstance()->GetValueResult(); - } - - PluginIR::PluginTypeID PluginServerAPI::GetTypeCodeFromString(string type) -diff --git a/lib/PluginServer/PluginServer.cpp b/lib/PluginServer/PluginServer.cpp -index 92159e8..2eac906 100644 ---- a/lib/PluginServer/PluginServer.cpp -+++ b/lib/PluginServer/PluginServer.cpp -@@ -27,7 +27,6 @@ - #include "Dialect/PluginDialect.h" - #include "PluginAPI/PluginServerAPI.h" - #include "mlir/IR/Attributes.h" --#include "mlir/IR/Builders.h" - #include "mlir/IR/BuiltinOps.h" - #include "mlir/IR/BuiltinTypes.h" - #include "user.h" -@@ -37,7 +36,6 @@ - - namespace PinServer { - using namespace mlir::Plugin; -- - using std::cout; - using std::endl; - using std::pair; -@@ -75,6 +73,13 @@ int PluginServer::RegisterPassManagerSetup(InjectPoint inject, const ManagerSetu - return 0; - } - -+vector PluginServer::GetOpResult(void) -+{ -+ vector retOps = opData; -+ opData.clear(); -+ return retOps; -+} -+ - vector PluginServer::GetFunctionOpResult(void) - { - vector retOps = funcOpData; -@@ -135,6 +140,21 @@ vector > PluginServer::EdgesResult() - return retEdges; - } - -+bool PluginServer::GetBoolResult() -+{ -+ return this->boolResult; -+} -+ -+uint64_t PluginServer::GetIdResult() -+{ -+ return this->idResult; -+} -+ -+mlir::Value PluginServer::GetValueResult() -+{ -+ return this->valueResult; -+} -+ - void PluginServer::JsonGetAttributes(Json::Value node, map& attributes) - { - Json::Value::Members attMember = node.getMemberNames(); -@@ -151,6 +171,27 @@ static uintptr_t GetID(Json::Value node) - return atol(id.c_str()); - } - -+mlir::Value PluginServer::ValueJsonDeSerialize(Json::Value valueJson) -+{ -+ uint64_t opId = GetID(valueJson["id"]); -+ IDefineCode defCode = IDefineCode( -+ atoi(valueJson["defCode"].asString().c_str())); -+ switch (defCode) { -+ case IDefineCode::MemRef : { -+ break; -+ } -+ case IDefineCode::IntCST : { -+ break; -+ } -+ default: -+ break; -+ } -+ mlir::Type retType = PluginIR::PluginUndefType::get(&context); // FIXME! -+ mlir::Value opValue = opBuilder.create( -+ opBuilder.getUnknownLoc(), opId, defCode, retType); -+ return opValue; -+} -+ - void PluginServer::JsonDeSerialize(const string& key, const string& data) - { - if (key == "FuncOpResult") { -@@ -173,6 +214,12 @@ void PluginServer::JsonDeSerialize(const string& key, const string& data) - EdgesJsonDeSerialize(data); - } else if (key == "BlockIdsResult") { - BlocksJsonDeSerialize(data); -+ } else if (key == "IdResult") { -+ this->idResult = atol(data.c_str()); -+ } else if (key == "ValueResult") { -+ context.getOrLoadDialect(); -+ opBuilder = mlir::OpBuilder(&context); -+ this->valueResult = ValueJsonDeSerialize(data.c_str()); - } else { - cout << "not Json,key:" << key << ",value:" << data << endl; - } -@@ -217,6 +264,46 @@ void PluginServer::TypeJsonDeSerialize(const string& data) - return; - } - -+bool PluginServer::ProcessBlock(mlir::Block* block, mlir::Region& rg, -+ const Json::Value& blockJson) -+{ -+ if (blockJson.isNull()) { -+ return false; -+ } -+ // todo process func return type -+ // todo isDeclaration -+ -+ // process each stmt -+ opBuilder.setInsertionPointToStart(block); -+ Json::Value::Members opMember = blockJson.getMemberNames(); -+ for (Json::Value::Members::iterator opIdx = opMember.begin(); -+ opIdx != opMember.end(); opIdx++) { -+ string baseOpKey = *opIdx; -+ Json::Value opJson = blockJson[baseOpKey]; -+ if (opJson.isNull()) continue; -+ // llvm::StringRef opCode(opJson["OperationName"].asString().c_str()); -+ string opCode = opJson["OperationName"].asString(); -+ if (opCode == PhiOp::getOperationName().str()) { -+ PhiOpJsonDeSerialize(opJson.toStyledString()); -+ } else if (opCode == CallOp::getOperationName().str()) { -+ CallOpJsonDeSerialize(opJson.toStyledString()); -+ } else if (opCode == AssignOp::getOperationName().str()) { -+ AssignOpJsonDeSerialize(opJson.toStyledString()); -+ } else if (opCode == CondOp::getOperationName().str()) { -+ CondOpJsonDeSerialize(opJson.toStyledString()); -+ } else if (opCode == RetOp::getOperationName().str()) { -+ RetOpJsonDeSerialize(opJson.toStyledString()); -+ } else if (opCode == FallThroughOp::getOperationName().str()) { -+ FallThroughOpJsonDeSerialize(opJson.toStyledString()); -+ } else if (opCode == BaseOp::getOperationName().str()) { -+ uint64_t opID = GetID(opJson["id"]); -+ opBuilder.create(opBuilder.getUnknownLoc(), opID, opCode); -+ } -+ } -+ // fprintf(stderr, "[bb] op:%ld, succ: %d\n", block->getOperations().size(), block->getNumSuccessors()); -+ return true; -+} -+ - void PluginServer::FuncOpJsonDeSerialize(const string& data) - { - Json::Value root; -@@ -227,8 +314,9 @@ void PluginServer::FuncOpJsonDeSerialize(const string& data) - Json::Value::Members operation = root.getMemberNames(); - - context.getOrLoadDialect(); -- mlir::OpBuilder builder(&context); -- for (Json::Value::Members::iterator iter = operation.begin(); iter != operation.end(); iter++) { -+ opBuilder = mlir::OpBuilder(&context); -+ for (Json::Value::Members::iterator iter = operation.begin(); -+ iter != operation.end(); iter++) { - string operationKey = *iter; - node = root[operationKey]; - int64_t id = GetID(node["id"]); -@@ -237,9 +325,30 @@ void PluginServer::FuncOpJsonDeSerialize(const string& data) - JsonGetAttributes(attributes, funcAttributes); - bool declaredInline = false; - if (funcAttributes["declaredInline"] == "1") declaredInline = true; -- auto location = builder.getUnknownLoc(); -- FunctionOp op = builder.create(location, id, funcAttributes["funcName"], declaredInline); -- funcOpData.push_back(op); -+ auto location = opBuilder.getUnknownLoc(); -+ FunctionOp fOp = opBuilder.create( -+ location, id, funcAttributes["funcName"], declaredInline); -+ mlir::Region &bodyRegion = fOp.bodyRegion(); -+ Json::Value regionJson = node["region"]; -+ Json::Value::Members bbMember = regionJson.getMemberNames(); -+ // We must create Blocks before process ops -+ for (Json::Value::Members::iterator bbIdx = bbMember.begin(); -+ bbIdx != bbMember.end(); bbIdx++) { -+ string blockKey = *bbIdx; -+ Json::Value blockJson = regionJson[blockKey]; -+ mlir::Block* block = opBuilder.createBlock(&bodyRegion); -+ this->blockMaps.insert({GetID(blockJson["address"]), block}); -+ } -+ -+ for (Json::Value::Members::iterator bbIdx = bbMember.begin(); -+ bbIdx != bbMember.end(); bbIdx++) { -+ string blockKey = *bbIdx; -+ Json::Value blockJson = regionJson[blockKey]; -+ uint64_t bbAddress = GetID(blockJson["address"]); -+ ProcessBlock(this->blockMaps[bbAddress], bodyRegion, blockJson["ops"]); -+ } -+ funcOpData.push_back(fOp); -+ opBuilder.setInsertionPointAfter(fOp.getOperation()); - } - } - -@@ -253,7 +362,7 @@ void PluginServer::LocalDeclOpJsonDeSerialize(const string& data) - Json::Value::Members operation = root.getMemberNames(); - - context.getOrLoadDialect(); -- mlir::OpBuilder builder(&context); -+ opBuilder = mlir::OpBuilder(&context); - for (Json::Value::Members::iterator iter = operation.begin(); iter != operation.end(); iter++) { - string operationKey = *iter; - node = root[operationKey]; -@@ -261,11 +370,11 @@ void PluginServer::LocalDeclOpJsonDeSerialize(const string& data) - Json::Value attributes = node["attributes"]; - map declAttributes; - JsonGetAttributes(attributes, declAttributes); -- string symName = declAttributes["symName"]; -- uint64_t typeID = atol(declAttributes["typeID"].c_str()); -- uint64_t typeWidth = atol(declAttributes["typeWidth"].c_str()); -- auto location = builder.getUnknownLoc(); -- LocalDeclOp op = builder.create(location, id, symName, typeID, typeWidth); -+ string symName = declAttributes["symName"]; -+ uint64_t typeID = atol(declAttributes["typeID"].c_str()); -+ uint64_t typeWidth = atol(declAttributes["typeWidth"].c_str()); -+ auto location = opBuilder.getUnknownLoc(); -+ LocalDeclOp op = opBuilder.create(location, id, symName, typeID, typeWidth); - decls.push_back(op); - } - } -@@ -384,6 +493,121 @@ void PluginServer::BlockJsonDeSerialize(const string& data) - blockId = (uint64_t)atol(root["id"].asString().c_str()); - } - -+void PluginServer::CallOpJsonDeSerialize(const string& data) -+{ -+ Json::Value node; -+ Json::Reader reader; -+ reader.parse(data, node); -+ Json::Value operandJson = node["operands"]; -+ Json::Value::Members operandMember = operandJson.getMemberNames(); -+ llvm::SmallVector ops; -+ for (Json::Value::Members::iterator opIter = operandMember.begin(); -+ opIter != operandMember.end(); opIter++) { -+ string key = *opIter; -+ mlir::Value opValue = ValueJsonDeSerialize(operandJson[key.c_str()]); -+ ops.push_back(opValue); -+ } -+ int64_t id = GetID(node["id"]); -+ mlir::StringRef callName(node["callee"].asString()); -+ CallOp op = opBuilder.create(opBuilder.getUnknownLoc(), -+ id, callName, ops); -+ opData.push_back(op.getOperation()); -+} -+ -+void PluginServer::CondOpJsonDeSerialize(const string& data) -+{ -+ Json::Value node; -+ Json::Reader reader; -+ reader.parse(data, node); -+ mlir::Value LHS = ValueJsonDeSerialize(node["lhs"]); -+ mlir::Value RHS = ValueJsonDeSerialize(node["rhs"]); -+ mlir::Value trueLabel = nullptr; -+ mlir::Value falseLabel = nullptr; -+ int64_t id = GetID(node["id"]); -+ int64_t address = GetID(node["address"]); -+ int64_t tbaddr = GetID(node["tbaddr"]); -+ int64_t fbaddr = GetID(node["fbaddr"]); -+ assert (this->blockMaps.find(tbaddr) != this->blockMaps.end()); -+ assert (this->blockMaps.find(fbaddr) != this->blockMaps.end()); -+ mlir::Block* tb = this->blockMaps[tbaddr]; -+ mlir::Block* fb = this->blockMaps[fbaddr]; -+ IComparisonCode iCode = IComparisonCode( -+ atoi(node["condCode"].asString().c_str())); -+ CondOp op = opBuilder.create(opBuilder.getUnknownLoc(), id, -+ address, iCode, LHS, RHS, tb, fb, tbaddr, fbaddr, -+ trueLabel, falseLabel); -+ opData.push_back(op.getOperation()); -+} -+ -+void PluginServer::RetOpJsonDeSerialize(const string& data) -+{ -+ Json::Value node; -+ Json::Reader reader; -+ reader.parse(data, node); -+ int64_t address = GetID(node["address"]); -+ RetOp op = opBuilder.create(opBuilder.getUnknownLoc(), address); -+ opData.push_back(op.getOperation()); -+} -+ -+void PluginServer::FallThroughOpJsonDeSerialize(const string& data) -+{ -+ Json::Value node; -+ Json::Reader reader; -+ reader.parse(data, node); -+ int64_t address = GetID(node["address"]); -+ int64_t destaddr = GetID(node["destaddr"]); -+ assert (this->blockMaps.find(destaddr) != this->blockMaps.end()); -+ mlir::Block* succ = this->blockMaps[destaddr]; -+ FallThroughOp op = opBuilder.create(opBuilder.getUnknownLoc(), -+ address, succ, destaddr); -+ opData.push_back(op.getOperation()); -+} -+ -+void PluginServer::PhiOpJsonDeSerialize(const string& data) -+{ -+ Json::Value node; -+ Json::Reader reader; -+ reader.parse(data, node); -+ Json::Value operandJson = node["operands"]; -+ Json::Value::Members operandMember = operandJson.getMemberNames(); -+ llvm::SmallVector ops; -+ for (Json::Value::Members::iterator opIter = operandMember.begin(); -+ opIter != operandMember.end(); opIter++) { -+ string key = *opIter; -+ mlir::Value opValue = ValueJsonDeSerialize(operandJson[key.c_str()]); -+ ops.push_back(opValue); -+ } -+ int64_t id = GetID(node["id"]); -+ uint32_t capacity = atoi(node["capacity"].asString().c_str()); -+ uint32_t nArgs = atoi(node["nArgs"].asString().c_str()); -+ mlir::Type retType = nullptr; -+ PhiOp op = opBuilder.create(opBuilder.getUnknownLoc(), -+ id, capacity, nArgs, ops, retType); -+ opData.push_back(op.getOperation()); -+} -+ -+void PluginServer::AssignOpJsonDeSerialize(const string& data) -+{ -+ Json::Value node; -+ Json::Reader reader; -+ reader.parse(data, node); -+ Json::Value operandJson = node["operands"]; -+ Json::Value::Members operandMember = operandJson.getMemberNames(); -+ llvm::SmallVector ops; -+ for (Json::Value::Members::iterator opIter = operandMember.begin(); -+ opIter != operandMember.end(); opIter++) { -+ string key = *opIter; -+ mlir::Value opValue = ValueJsonDeSerialize(operandJson[key.c_str()]); -+ ops.push_back(opValue); -+ } -+ int64_t id = GetID(node["id"]); -+ IExprCode iCode = IExprCode(atoi(node["exprCode"].asString().c_str())); -+ mlir::Type retType = nullptr; -+ AssignOp op = opBuilder.create(opBuilder.getUnknownLoc(), -+ id, iCode, ops, retType); -+ opData.push_back(op.getOperation()); -+} -+ - /* 线程函数,执行用户注册函数,客户端返回数据后退出 */ - static void ExecCallbacks(const string& name) - { -diff --git a/user.cpp b/user.cpp -index efc4158..605e6f8 100644 ---- a/user.cpp -+++ b/user.cpp -@@ -117,7 +117,7 @@ ProcessArrayWiden(void) - - void RegisterCallbacks(void) - { -- PluginServer::GetInstance()->RegisterUserFunc(HANDLE_BEFORE_IPA, UserOptimizeFunc); -+ // PluginServer::GetInstance()->RegisterUserFunc(HANDLE_BEFORE_IPA, UserOptimizeFunc); - PluginServer::GetInstance()->RegisterUserFunc(HANDLE_BEFORE_IPA, LocalVarSummery); - ManagerSetupData setupData; - setupData.refPassName = PASS_PHIOPT; --- -2.27.0.windows.1 - diff --git a/0004-Pin-server-Support-Plugin-Pointer-Type.patch b/0004-Pin-server-Support-Plugin-Pointer-Type.patch deleted file mode 100644 index 82472f7..0000000 --- a/0004-Pin-server-Support-Plugin-Pointer-Type.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 7e56b74990e5f6ccb9a2896eeea0d60e1e2b1f21 Mon Sep 17 00:00:00 2001 -From: dingguangya -Date: Thu, 8 Dec 2022 20:50:23 +0800 -Subject: [PATCH 4/4] [Pin-server] Support Plugin Pointer Type - ---- - include/Dialect/PluginTypes.h | 12 +++++++++ - include/PluginServer/PluginServer.h | 2 +- - lib/Dialect/PluginDialect.cpp | 1 + - lib/Dialect/PluginTypes.cpp | 41 +++++++++++++++++++++++++++++ - lib/PluginServer/PluginServer.cpp | 28 +++++++++++++------- - 5 files changed, 73 insertions(+), 11 deletions(-) - -diff --git a/include/Dialect/PluginTypes.h b/include/Dialect/PluginTypes.h -index bb8d81a..1329b8d 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/PluginServer/PluginServer.h b/include/PluginServer/PluginServer.h -index b28c6d0..207c018 100644 ---- a/include/PluginServer/PluginServer.h -+++ b/include/PluginServer/PluginServer.h -@@ -187,7 +187,7 @@ public: - timeout = time; - } - void FuncOpJsonDeSerialize(const string& data); -- void TypeJsonDeSerialize(const string& data); -+ PluginIR::PluginTypeBase TypeJsonDeSerialize(const string& data); - void LocalDeclOpJsonDeSerialize(const string& data); - void LoopOpsJsonDeSerialize(const string& data); - void LoopOpJsonDeSerialize(const string& data); -diff --git a/lib/Dialect/PluginDialect.cpp b/lib/Dialect/PluginDialect.cpp -index 63ba167..001fdab 100644 ---- a/lib/Dialect/PluginDialect.cpp -+++ b/lib/Dialect/PluginDialect.cpp -@@ -35,6 +35,7 @@ void PluginDialect::initialize() { - addTypes< - PluginIR::PluginIntegerType, - PluginIR::PluginFloatType, -+ PluginIR::PluginPointerType, - PluginIR::PluginBooleanType, - PluginIR::PluginVoidType, - PluginIR::PluginUndefType>(); -diff --git a/lib/Dialect/PluginTypes.cpp b/lib/Dialect/PluginTypes.cpp -index def302b..0fa003a 100644 ---- a/lib/Dialect/PluginTypes.cpp -+++ b/lib/Dialect/PluginTypes.cpp -@@ -72,6 +72,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; -+ }; - } - } - -@@ -94,6 +113,9 @@ PluginTypeID PluginTypeBase::getPluginTypeID () - if (auto Ty = dyn_cast()) { - return Ty.getPluginTypeID (); - } -+ if (auto Ty = dyn_cast()) { -+ return Ty.getPluginTypeID (); -+ } - return PluginTypeID::UndefTyID; - } - -@@ -252,4 +274,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/PluginServer/PluginServer.cpp b/lib/PluginServer/PluginServer.cpp -index 2eac906..74974dc 100644 ---- a/lib/PluginServer/PluginServer.cpp -+++ b/lib/PluginServer/PluginServer.cpp -@@ -225,13 +225,15 @@ void PluginServer::JsonDeSerialize(const string& key, const string& data) - } - } - --void PluginServer::TypeJsonDeSerialize(const string& data) -+PluginIR::PluginTypeBase PluginServer::TypeJsonDeSerialize(const string& data) - { - Json::Value root; - Json::Reader reader; - Json::Value node; - reader.parse(data, root); - -+ PluginIR::PluginTypeBase baseType; -+ - Json::Value type = root["type"]; - uint64_t id = GetID(type["id"]); - PluginIR::PluginTypeID PluginTypeId = static_cast(id); -@@ -240,28 +242,34 @@ void PluginServer::TypeJsonDeSerialize(const string& data) - string s = type["signed"].asString(); - uint64_t width = GetID(type["width"]); - if (s == "1") { -- pluginType = PluginIR::PluginIntegerType::get(&context, width, PluginIR::PluginIntegerType::Signed); -+ baseType = PluginIR::PluginIntegerType::get(&context, width, PluginIR::PluginIntegerType::Signed); - } - else { -- pluginType = PluginIR::PluginIntegerType::get(&context, width, PluginIR::PluginIntegerType::Unsigned); -+ baseType = PluginIR::PluginIntegerType::get(&context, width, PluginIR::PluginIntegerType::Unsigned); - } - } - else if (type["width"] && (id == static_cast(PluginIR::FloatTyID) || id == static_cast(PluginIR::DoubleTyID)) ) { - uint64_t width = GetID(type["width"]); -- pluginType = PluginIR::PluginFloatType::get(&context, width); -+ baseType = PluginIR::PluginFloatType::get(&context, width); -+ }else if (id == static_cast(PluginIR::PointerTyID)) { -+ mlir::Type elemTy = TypeJsonDeSerialize(type["elementType"].toStyledString()); -+ auto ty = elemTy.dyn_cast(); -+ baseType = PluginIR::PluginPointerType::get(&context, elemTy); - }else { - if (PluginTypeId == PluginIR::VoidTyID) -- pluginType = PluginIR::PluginVoidType::get(&context); -+ baseType = PluginIR::PluginVoidType::get(&context); - if (PluginTypeId == PluginIR::BooleanTyID) -- pluginType = PluginIR::PluginBooleanType::get(&context); -+ baseType = PluginIR::PluginBooleanType::get(&context); - if (PluginTypeId == PluginIR::UndefTyID) -- pluginType = PluginIR::PluginUndefType::get(&context); -+ baseType = PluginIR::PluginUndefType::get(&context); - } - if (type["readonly"] == "1") -- pluginType.setReadOnlyFlag(1); -+ baseType.setReadOnlyFlag(1); - else -- pluginType.setReadOnlyFlag(0); -- return; -+ baseType.setReadOnlyFlag(0); -+ -+ pluginType = baseType; -+ return baseType; - } - - bool PluginServer::ProcessBlock(mlir::Block* block, mlir::Region& rg, --- -2.27.0.windows.1 - diff --git a/pin-server-0.3.0.tar.gz b/pin-server-0.3.0.tar.gz deleted file mode 100644 index 82e1af8210ed6cbd4bbb28af5b5218178163bbcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20496 zcmV)AK*YZviwFP!000001MFN|k0Zx*)~om{DwKkd7Kd}$of&Bb1>ut1UCJDCLUOcP z2m(>;E|QgPcDMU7v$U{)99RL8*fEkgFG&zbiG#dYHvAIUUK#o^*^Ba&zmRiIRdrXB zoQsf^N}xc{%|zdn||GR7Y-`_s~dwFggTyTBE^}jtyrRRR@MNI#OUK{;?5xA)*;^(!-W&XdrzwZBs z`-d<5|0}rOi_?ixH!FMI>7x98>E)0obM_X)kENH>$b;YKNfO34wzt7J=INvkkZ~Iy z(|=oG6#R*B611Gs%ae%vj+q`rv#s5|`c8fK>)z*!YxA|{|IH(QUvy=h#P#ICg%*G1 z>k|JzytaR^>i-AV4t8Jo|5tF8oCWB6ypXFJRzLUyGxRrO>gJGxNW7q2Y_1$Wz zB&U_*ez()S$C^jS24BI2~jP=@gt0m#PFl%k@?(V_4bKx25cU#t6 z9a}2LUOJOLYqI9M?^a9Fcf8aU6(X{Y1#IBg=>tr8W$XD~rB_%#Ol084jQcK&MUqH= z7C--WfO4gI)cAILeDkE!ZH@1CMt8=Y-f-0DcE`QOQG49#3|PMhd(4M|JjO7h*J=z} zZ1*~AHkx8&@HX=JuzcRc zZugy|4HNOUnMix18-tVHr~|w1pNx)AMj(k1?*G*fw2V5v#^4^!+MY%R2$mXBQKj`n^ZQ%lm7ip zY%AY3HmWR(yYAQ(;Es~^ZHBhmw>rJf2;wlZy^)D*IidlPFqEDc2TFdGtvGSta$b84 z;=uuG6P7 zYup_6yCWH4y= ziXu0B0WNjQ)s^XUH@folxixzhh0fL2#?fmG5Q!_VZ%7~$q)R|1!2;#E0Kcd}%EU{> zw1O~+OOR;c9xj{T%QmxeOO4W`oBg9B$RiZ{T4S*7QNQ_6KWhwb582ihO$yTF!VMXE z3??{X_(jHdikm>YDUeg5dW)VqTQlJkM{kuC%eM!|&2jViczoPFx!vhmGmEyTZ@1bQ z*@i0*$tF9>tJo~F&2N!v$YJ7*j(Fh?iD)KuT8VTF`6uGhvQm7+FlTm}z~-vwwJ`F%!WGUWIf57m?OR<4ZxDV=xO!N4Ubsp2a`WU?c2|ca zs4tC}mU*;VdqSDGAQI`1Q>aYX@J<5(Nf|%X!Jf+J?nKW3b};G>sj6ulcS;-mX#^$> zs54u}Sbsd{d;14*x?n)rJgvt8`@`Z58m9CL_f!c*>xc)!NfXR}mHY_-SO~VuW8%P zD*z1vxq4nn|I`{ATJmNZA%ZIpN8oPAM+V&ta0WkANp=$*QoUaFLMkxEP*GszcJHL4 z2)1Mt=hSa?y6xe`0e{_&%2!((gp&GtA*K|K#Z|9AV%nUu$5dizL@6jcs|>Qnm<@MS zO_tG65WOz_^5&`bo;FTZ^EyXI?N+BTYO_D;_qz9B8;n^FsrFIHrj}N75iO}cKV)0S z>y?dQ41#r>bXgWYTUYv=z5dwVbXKVQMcF1s2bcjkh1 zr6c@Ulr9+gj)-EYI@n%)r^epqehO)vfljZVI|;kWH@3IW&d%zbmZ=BP48kKV6>npp zV59cnXvi=YH2V<9sTg9n`U7?{Y}eSJ4N0YSLK&z=qgoy8ecU|3J49f&&RThCRWE67 z%6dm-%=i#a7lQjNft@BITBuGB#7|evV$&dE5U*=25|9Ml)WO>|O$x`lP%B4rlHz^F zV@A~+;Ks?44TYnK>;nBLNN02Q1`DR}LBhDeN%8HARlb5~jWH((myw*!6Be8SEM>qF zOq9uz@idtO3jHpvr|E2(k<59*V9{B`ee7Y;AT0-r0WsqqYZK`;CLpxJ28nyYxI}Y(gGWr)a5s22^<9{zI(nLt9>~rlRFOnSEm&u_ zf{6GC(mWSwvL`qXR1!;x?YGEK< z+28s7DlHd)c$DA`p){f19_j$p6p7eS1d+la{aw^>vX#rfa>_Za(%o{n9I()$QLdG!}JlUCY0#eJGsST;(FEi>%u2@6557d!*?H`u~#GKw{Uc?qQY)3EH>8Xm|G15`KyAZDAELn#3w(kbf z{k5QQ1~-XgibH5=xeG|&Y$J03B|5#W1&2DDpK|G8$)x??ic2+&rf7f;*QUg?xL~3i zhyey?;Y~wy7uUwHk|da0NJ55NO`-xD5D)kwgq2|;gmy4_mWPM&eYGD$$BTG}=#?00{??`2-}inr&~=#4yW=7%YXP&tb8^Bd36A63R|k zWnJg%@z}(vX~F$#Y*l<(dT7mBcSK%ijYwd5Yy4A$JR(a$xzIKiA`;$`VZ}>=n}D^T zonSk%YLqS^5Jgk&P?D%wIWiOK8dE485lnNfH!+m!9KTWHt3HsqthHVyK<#iQmu7q* zv4T#>hFy(B45dKHhGxO@^O&z$PLW{L4`6A}gl#& zWJhNa&hrU;q`sCuLocv}E^DW~HnQ z3dPGf5sTOk;gEAvfhokH9H~br^<(B!XeGm1w$N)<7%5nRC2f=&U|gu#Da+G}3yPN- zM&6}}m!~H2zzCtZS7VQ`l{l168l*8e?}A77G4w?_Ix>(;#B%0S><3ds9g$!+S|SFk zau4LqneD6f^12JJ;OlJL#se>fJhlKaJ}y=kWpiL=BEX&iG75_1z_h(i?u4=UP73zp z;j&Hu@>b~@0k7qLDiH0}*=>YXxNI}qzCl)On5yKeZFOTYW4W0fl?7x;W(kO42mzi6 z#Stz5a0t5ugcphgBxB4ELZ9cJNyHj{;BS%UW7si%+yc}S&9HC^mfTC0ThmCuCkepr zG;lDGuVr&x|KWnB+JYJ2V6~JVQqVO^LB||}?*9YrRA8D26Lc^rIT8brfWcT5L{%25y;|DC-dhd) z;8YOGGYnB39ZaW)^B@Tb55lkdA0kQ+B}y?_9MC{nqe2QZW@jh@r6aQ{4?_>j&AK}CRmAz7X>)V z35xMpm)bcUCs)qWY|H3lK}Z$IC@5C6L<5;jF{(Yq6dJjY>6B+smC6q2qNqJ%D?B!U z&4ruB_%i7NHLMd|6$-A`*+AHxp*k(S;LAL+twte;gVJD|LOi+v<&jDdHo{^l1Ua%J zL^SX-$TD)VY*s1!oJdy7OCb_SZdwZ=l$NJ~2Q`t(?ln)Z$Q_$68 zY%Px=E;DJQiKY9Dgdr52;>wP-awHOPu$sZmRtZnl0dTasIcwo;!Q3Ef=wW$wtZD16 zVOVqp;-;DfCdfpS+}-rvR10DQKdT`XuN=9l=xJyWb8bL@7P1U(6UC`KE=uymrFOEO zs*6H%s~EI0{p-RHRbB4&N1bN749@o;A$glQF@EFS}yGyU958WifWUKPQWg-5+%4SXGSiKZ{W&O@5m*QgMd)a*sxXXS>teR_P2fS5(pi%a zYKXjeMTAmhNBb5RgR!Bw*9T05NQIChAr}&7^QZl&;#J63lt$78^yBR}}iJJ1VqgvPxy85-2ESpNbuQ5}<0;90kU8cH%=8jY(-wP6)l%3vCewhTSC_}fMQF(`HgjkDHNC&ZSg*pgAH?UNq7gFd#HAq2m(S`}H*ft}j5{;csPqc@!mHlzS0slz&J$(TwfJhYv%yMRAIF3Zdb zGFB%`Rlri^jU`qd21tukyyRW5TCOnd`*F@{1$o7$!D@+WkH+?8LAh1zYeC2_H-@Y; zEVG-9VP|NBi{D4+pN!bu#$eFsjXLci>ksT>`Ti}|=-p%A?(|v!cceN2et_N4INyn+ zxZ+xE(%gfnPs&Z4T0)UaqN0K*S`V=x%u#35ZP!5Ry{%5~7JliWebnxaYV4>zXx;%X z8#g=M&gdSQ(5=p>*B+|Z2O65jabo}qJLxtC?D%AG+#j}8wpFKv9-b@!{~;_Y>C}Nv zW>i&JG#AiZ6oipPcupIhf_32#vcEjyTK!VhZH!~UM7UiOu4PP-Jq{e1mB}io>vLA> z#@Yw1>&2|Hz1QpT*@zS;btRujj}Ff}n0Xn%A3q^J6b-oLQL__xgi70LwV0DEFrdV4 z8Tex6NkCtYsMfO6?pmRhn{|FJwfBkw3fR;4?gVF838_*t6Bxog?8-1=CAnz;Hl2GTr?62F9W@>7&NqUW6=%M5f+7;7duRq+`eUimx8W}3;y6;miz z)C@qz?uOPmj}{b(47kpun7eZtMfqu&?i@o*hN>KkRnDMTV-2?-x1Mr#%%J9T=HEMY!Kb69BV+IKVoLvR|37%34u*~v%@0YW{N1X|s?Uu%v zD5~nJ&#I*BtkMenKgiw}uzb`I|Gg@sYMsi|7~ln10zmwX4_zHtY1=xRMPG@R5YHcE z2ccBdD+VA=z(g;`11dFI_eo6@r?JXzz{(J@snT86G@nQ1OtIeU%Gv6V7&Bo8A_osv#1Q>u)OLI zCe$tCg_fN$WS$svzwDJ${r2+~uuM~~g3!;y9{Qa#BxAMI*57c#Lj!xjc?kS}3BL{S zCb12LD6n9RoL~*u3~bGxrC@LX2_P-_t8ez{Zb^>UgT=MrHuI(M{uKoR&or4#D|K+Q==<93R0!pP<;9`#-{pGVqKP(+XFrz=a0EIQ1 zMvw~-2UMB<>Q&Z5P~XV}9MVyEO232(=^GN=LVj1J9~aQ27ho5QY7h0PI3$EzSuZ{L z?cYB6^B+Eb^wHBF|KjNnzW40WPd@+o$IpKG=;@FC=JBKdc=q?-Z;3_lXZNe^aoFW_Aj4*_E%4S{n?YB{`-?p zKYa3|zyAEgkDmO+KR@~C-(aHN>*v4y1yFtZPw?;ixa0K=*O*%Q>BoNt!>W&e^_you z{>jr1zxVjl|6%W0o0~e4{qA3JN>Evul_kpQsS`X1aTN zW_r5&%%kTL{+VZ@%@I~$E^ZGx}=?K3s z&uV}FWO#7!_vJZak4RAQSaoPLs?Dnl7xa?rx2|Xx@2>p#Xyy55@Y4;A(M5*@JGCz_ z^CBO9U!VOIVCsu^wcFn?n8|dyE1kpj+)lu(&n`d*tSp>Ih~;@K%^(DAr&pRd(<{CD z^4rzBmmMk%jY&9ylu;hFI#g6J_ub0X$Jj{o(5LscTZ@pT-CC;OcvPQz0Mreltp7;> zw1;!6_dc)x<;Ke5rH+o{$B&n%RQPh;sZ4(epZW@mjt0Nd8RM13t?+t%N>@k(yx6~U z>`2H5X)GubgTzyQbR5k$odZf;Ara)FF))j|w3F?fL3YHLWHPe)=$HESs~sJFucDlS zr=v%_>=rM)R`Z|Ko?c!3`nAW}^Ce|SO;wVBs%W$4 zVazd7*gH#q!=AizuA|q09joSYN(^T<$`#RqD|6547iXvxViO=znQ8U?%qg|M~G0{A9ciXDi^bXb-Q~uRYVQ z+yp^X-aC;iOk&I_RmFHzAGk$~Dsy@#t5EI59TE%WJt>qGLHKY1qEJ!|3bw3HW%cEa z+S4DjTaUHdGf^5n^4r=oqn zxbom}{rV$LseWswervAw{8w#eS*C>Q>^h9hWo==0_0ebA!<*WLCFe5tSXzq)8p4vA znY*N&zwFcsAooQlMlrp!qt77w_}r`8-`AFwR_6WzOx2#w)bHLy%D3;6S{ALcd{g`4 z`m1|aQOn%?tbS)6*mEkFy>+1(F8dr?O3H5^;oRiM=Kqlv+SD>wkgxT{f9=J1(e3!J zZ~j@M|K*TcuU$qn|KHzji~qLQ-`Cyt|F__2G5lLuttid`$E;z*5>vQ)s;oy6gZ$}K zx>Rr{2M>k^-=(dt*$KtH^Gq-{e7O58#wr8Y;0Oj7z$8D$OX1TsiU=bHc?Sx)Oiaz3 z4aZ{9SOB++u$dz)U2!Rd+jACP;nQRi-1nVl1`D}DwG>l>`>BEYWhQkMb|h{ zo#-fjIGJQgNgjyRjlnc{@C+V}3E&3y@Amq=-B30wLj+E-M%ggvB8vwjqlq}i;xH(R z_!9P15upmBPf_>Tsk^KxU8B*&P;`7Wq zSyQZqa|+f@UppQPEBB9ogrPl=<6HGjr8^_J*3Pr^uZ=u)v?F(BmTY|33U5^6TE)m^ zm`gB|Uz;{j#=)ZZZR$i>&E}Hj)A{ri9@3&23v=lXacmIJhNUy*gy3>Ww6N$zlMgPz z?w`tqJP4_oKTBXA0i?5I&39Q6ENpOeDtWuDSo_)N)0i|{FdH`S+x(XL1T4#=qXmobql3IQekcY!ZF;dJ(a4@X6-p_*q>*qk| zbFvro4<`yG+$!K^OOPU6uBjf&R*Vi@7TXyfJ$wekccBkOSmbO1|B*Oo@;T?-EPyJU;H>U@Q_m zFal`PN#nFoESwmRjY8(gILj%im6Lkx3gN{w*?}h1^Pxt%JKrrFX-7dBD-}-U)M?yV zmM4ZAHm2cRb1!|fn%3I4L#*>1;Eipq>ZvS98pD@7ejz>oTGr5}|M^aY&71++!2Hji zp56ZT{LdCVYxe&p-UHCY{^JagZT@F(-|n{k--5>$h&7Z=;fGx3b~Dy~w&YoJ{Bt?j z3_Gv^{ol7|Z+rfKE1stPzX^7rnf~9i#~S~$$G^L`t^c>;*?}A3_3eKd>U0G+>ZJHd zy;Ny3;1(JDZ;~CtDyGtECw-s|M#qjRzG}IIS8=cn4_%cLxk+&C<-o>XABEz^{3IvE zZ+3|m%gPv^pY7P8jPj@(>}Z2H+G{>OEI2Eq^~(no9^4zxN))SfDS>#`Eu73kAGZ_u0pPFX;dF z_L8(^hlM|J{g zJ)zJFVlos7;woD5V8;#$3~kTQuR&5=Xjpuam`_)_t`1<)r{7A#4!)%-6=;4V&@?~J z5>nGSJpYYH(_$*hoNDZ4^-6`9^*fj;y)-YtK#4op+?E36+IZb=rPY2m?OCV&uWaO4 zKok4FyBBt?f*8||2O0SSnYqMP*iew*2L@r6t~d@NQBn%0U)Qt z<^x2F2U5^tl??L%Hs537-jMjfHEzoAzJVse@r)aiw^@i z3BzX;R!|3%5A^O=-aB*l1Cf(17DvS#2~r6Jutx&{y_~bGIk0p2DPa^&vu|pehGAl@ zCqUD{Aja@5dH^mA9*-oCM~lZfNg$=m51oe>r?vtJsVKYH32BV0o39w9Qg7&Gd1ct? zygJRIREx2sgRz71n8KP=M0Am7mGDM~>?xgGkVUv=#g$U5Dpr!-4yp(5#b|LKE$QoA zco>O&(P9EA3Ng@!N%r(@M$*x za(@Bi77r|ti>{l9--|Ia%AV;EHI5z9=F@`n9DZp6mo@-&c~=r9Fzpqj-y zgc9r$o+(%3Ng{h@v?w`r4iNgKD84v&1>uPapkySni6_D7a5w>MCI?4?@pw4iXd=mJ z21%;sc5A%$BR}h~{~Mb7!Kc~$&tAWM{-=9Sd;NDSp0@pO+y8B{|JE52v<~*!5uR$y zj94e6UDipHCPs}-rC_l`JZxdKs05@>OqU2}=<+D#X_9Siz>imV78){Iq@|oN>oF}D7`Ad{OK5b3+y~m$nf`0RyQ#I zxWR-X?otd5Wm>IF6*5lW`#8k_LPr2fu~4jHOt~`ALD1tYLiBN(0mA4Ts2=E6hmy)- zN9!J*N6C6Y6I2*QcC{$#B;0OJrGZ%ta}t!oXt|i)Crf=`ikoWG_A|ltOG#x12!LoLOD`Mr*gQ6 zXO+r~SlDY-Fmp&rIhiU^kW(3dE#XADG^ViLph%WaPq!|SMnQNNWhB%Z*0>q%NH$ZM z+JFdeju14cuggH=)iaSYcsJz4HdjSDazpmNMgNa~fNadiXzc&_{oQ`s`7eJ@Pka4u zE1tIh*Y^Lm!T*EgAiE1RpbS@m;^~wU;_+k$nIR64sQLX}J-abAWSA3nhwBtX~w&(K!^qQqya4U3ma7S}GuI3<>m-I5rlJ zCl4ldkG3UXhgqB;zbs{~DIji&8st{^#7u+y22)JPH^w+tPpvV{q~mtz`+|AnLED|_ zAWzH4LNss=)qHhYG0aOOq>y(!jxC!w4Zrs*-DEP^!XZjk_N1E7d+cx_n?X1ajbNY8 zw~u;?>4SVhDQ7>XP`cyj|4*u=#A!bRXQ2MB6IoC%dAwhgZJ=TxjDiK}Z3F4;mXZ8@ zQc-;^qwVf7(02E zEDgXkyA5e5S4dS1ag%wQz$~T-3t7BiNT7rYRj>x;VmNC~C_>aj{N`^%H;GSGtF()B zf*LEZTdpM_g5v1}1a4_HU6El3h|;SiUShCRN}V=A5g1G7Ol420nZs;Ty#OSpFdfDq zIIT)Naww#nWH3gv#NopP&7^_LS>Wk*th1mlVEp)v+-hfFg`{D3dAdk)lq85Fs( zV9UkAM@m1+u~U!9CL)7ZCFZ!+FEja5OfAEh1t9=;qu&n12c!gY)+{9w6|*xc!yeA2*t%h7ZNO3P5H}FO|GC^Tb4N0Q_rt{1X}sAcUFP*?1A{9c4~_?Aw7?Y@ zyH2Jo;7!nYj}9Al{FhK$I*^b!A~|j`2@LFPKUX|HC8mM~$SZjF8pi0V@TIhrvs(08 zr5_>OopgPhat5!$L~0;dMztY(|9-uq{mR+a%C=~6Tghss<#N?bE2ZY0&8OFCG`Cc= z0LH>w(?eY1!Aztb1R5~hl4GXqO4EzSV4SI7kE6^c|<9}?$)3*O@`@g;G|A&A?da4RF zJ5pun$DmKARG>SOwe1J!e!I*6c9Z=8I30)A^U~QvW80hPdtI|7NvDw|@H%ZtHPm`M z96KD2SsaqaP?9&|@ChZaqstoBq;Ab%j$5)E7Tw8AZ;HnvPdVupz?dCt<{nrP?cTwk z8-tLIZ{iG~AeOQjzDCrdCtyYrQ)Z&(eDZCW7R&|<8Fi>sn5Hd#Zhiy@#Q`M5{p6T1k3f~Ph7K=nAYGR`m$4Yiu^-h_vvXl8# z&XT51r;5;03{*=a|9zFTTwwMtL1(%GfMRpGk%B+;@NM>q$#mO z6~;2wHPgzHphp1>ClFEKm^Vm%AKpS12G=E$NFE5|g|xcoM>#CfV+EzV+T>(=N_aFR z|4c*_b;NuXm1%%0mugx(;l&%YO_j9omgnXKjB_eytVx;FIq7M5vGf(Vy&wj) zXLBG^XdLRdu4otUuKf5&`|`5(@ca7gukikA=4S2XU4W=xy|2yR(=NQI|K&06jbUn( z858U+HG5Kx!}7yRZ?|)UFvz3MOwdYrLcIsb0 z(PkfG>phvRpL--&!y&F0I94j8Uz@p*Tf6K)|vnX#C_0 zZq4wmi+}oWJ3e;Ex8JQk{*+{vgyZ++%PU_m)|Ren3tvzx)c|_v>@NK_6>NU+We2P}ZGgZFydHY65)y(=@=sr_?lSiN+)2 z@p;Y*7;n%ntQ@f7FpOb*=*q^!r5o%SDkSa2S73-}kk|it4$Ri8FJ~>oJD(BFYFLYP zk0$wmDhO44s#?huKFZ@c&PGbS%;97sz}Yg>V1y^|Fsg-+pn!IW9U8S03Kp|NJbaRa z5wsFa8PF!P=SXvmEnK@DSF@ez5(ZEvC?*X~3^c+lk!-d=(d}6*oH;pS5>$h4O(de6vx&wul!0 z3%-j(V3kYoS(^RWDm@ucBJ$n`{9IihhNO#IMg(1epX=KE6>Vu=oBc++d<|4GX(TYP z+RU;xdtRIU5wsPkFnwEx4~tma0Zsu_H!M*x-3%XV!Ut{&-XA^fIrDZi( znmpO8N1$s21q%eLMAE~e9)LC`bZz00 zc5zWh2gXG{sNC+=|7-7Ao7*^!{A~S-HLAocCFaakM@4`Y47%*9>4#4S%x6PTAf>SG92Cc3GzRJ&r9r=@Lrcr zHWi=*u<3=3?Tp^LciwR{!>1veyV$mj2;<|ELg6KxbG$~g0!ok*VW}h;PCsiwT@l$H zpM!c4LkIg4@auB!N(L6~UM@WsQy^~^F#2>ImSDUQ;>2gSfOGm}&DE4UKYeuTw*F-A z!H;+U;}?%U{58noqkDHj8}GgSXAmt1sx54Sqw2%~9h_o6^k%7=P+Ry#Azve3!xY{} zpT7r+2IDEL8izzV-@nlT(RV?D+KT~5LUSh;K!v|IN#J~|wO}saXr`BX0WG%wQ2o^TO`3F2H;s2Eqkl8?XJU!+Npp-K6^#t6bju?5B_J z{Rrj&*80QGehEa>+QL53!M~TMuEe`O9$`D>m%9Ak*HFwTowM2Qp#S7k+7yo6|3yZR zp7O)E`uP9lXJ?}Mzo*ChzlU;-_ka0JH{SpKs_g&bZ04cb>)iI;SaWUq@~1~^d(PWG zG&C9Z{K3Dn5jDdPWXhEa%qVK&Ws?Ip;G8MdYFA6;>!GmX9hNUpWc;sHuReLi2lE=i z|9fWo#LU?L`w%WC|IeH+T@O}3FvD!;<;1TZ=<4JDotv7q^MB+|=JO}U^Zy}SrAnn3 zcCS`o5<``L$LEe5=_5z*6)sGQAQJ5oyu$U7I@RN;gFKNV!sS*A$N0si)ujuIYw!!J zO1G2cM)@2?;a5+w^vd#u7mF*)FRXd18!y0o%L^=DGE1hPHp%{`E@%H2&OH0n#t7s8 ziId~_KZkN9@_(P^fqvuv^z?~H{>Pcwsqy%K2$vk>d60BtuwNB{Ms%+}9NWbck%dQp zhJJ+ujsIfEN5`m(7nUxpW5F}cb}-0fu-0v%$68#)WkB^P^zY_a@gvq0|(Wn1U zot%l}f6b5Me;m#=w*QRnKYxSyUyZ~dR-V^`O7rS=g?Hv>?c<3b=S=TTq|qWA9Cm?VeOl#hgwmrHB4aDknoUCl!)` zi066CY4{-N_W@sJ<=$OcURzHTB0TXysdrg(1of5V@qd8%pFQ~qz6O3IQsR=zv_u< zA|+{8f57sQawnk{i?D zRAqzY0gOGS=6GghVQp<`Z6M|GX=^0o>oBhY^nYpg9kq>Q{XajOkJ|roC-Y; z`u|w}|AOcL{dymNucwp$cVyjuSaY5*8qLLI*Nw@ih{^3lf=Nng#dA^-hc+5jklV&q zR=8j%rCv0XVTp&|(H-3*b$lxcU96%R0Z=F;=c`LgPz46tXUWzwS{Yv}?tSN#Ba$GP zd||s3ZsR#999SwODqVvbjQ%eMJL@}i^sQ1Tv`W?XsjkeVI2g|JW)`_x?MA&&z{ZQ^ zW`&^vjqr0&thot5D;+&aq*bM}r9KvuXD~>=#Z?en<~G}>Pdk9}1cf$eD&q4*fjZSr zpGF!Pjl`uQ6cRB>ZJ;Rm+GCg|V1{Ffu8r^v?U zr_)BmvBC@OWjCwsu#>^2vta;VRxv4V$~Va3bZ*YwBl-z6)Scp>rNks;IZf(~s(rhb z)gRMV=aHRcn2r+dETWM)1#Ec9bW5ixks2c+k{Kb`LC9sSYz{1+k<690bS5xU^?!>H zu~PX8E^eXVLGA|06u3cmnZs_VH%QrJlJNmEvkcUNbGTq*a|PFmnanYme}&*92P;5l`ajw*|xgilaGq+IBIr#glK^b&mjrC=n+R;|n+$9m zmJsx-;~Larh8WM+!zN71h`WgBi_PxUTA)A-ES>U$oF6!tWDY212QFHC z)pk(A7E#H#Lg~Ai1BR--#r-)GP zY?kv*8;=VGJ%T&`PCg&bTM?*vo3Vv>sAeOzvR2B7kE~^LiIimVMfu~K+bGt4K5Yc- zWJO&OLN!*Q2#BI~d}dmh>k%~pK1LwKK%zXNDURwuc*EY5{5dLZP1>|wU4<@uJ!*+U z=122oM?~QX6KHc`hzOLd#>61oX zGe4299S&G*QJr$^@wwa8m*FH}K@I0n9i(RT9R{w$c%2CR`O$zsKN#k-BceV#5cuh- z(ZDO)cOv-NnbE*2gSZ3yXj~nLsiX09AeN5E(ZLuxB0mRX=ZM@KjG5B7I1FgRA{hgi zTZe}MYuUCPK!xpk7^t?ro6Uz&Ynr1!7)EeDix}aeU1KkMmoS4KzyxX_)n+&hGKbnp zZ6Z_XB8!JTvfR5etPnjKwdLe{iQ+WHtO;`igKGRu6fLPcj|5 zSm>OR?KsjzkK*#BxL8OD_8-2id2$=W2=>2|@c-EUcL-O1{;Or}s7Jv1*#BmyPs~Q_ ze>3@$WBcDBTx0v+*#7rrxBn3bN3a1FVNf#@K#L^GWthQBZ6keiwaN0O>CeiT%|U;# z87&h{4P6IjzHESDX`knZHY`RmDyw(!0nQ}Eq~Rg&DPhLS#dF0MHqI8;mcNBrdGooc znOx2;1cJ6yTwGYE5?{yn{JaHVwA!vVL9Tbatzt|31SRj%^2JNb>wjMaiM&ABF<>Cs zeeK7+H!*3)-lre-?)-N5E%{-tVrpMJjg(d&=j`<^IQ-Y&JF#MSQR zWgYh`n09s>gDezVowj5Hl-vv@x;*5<7G=ewv`5YyRC;NDa;u2_Hdt>$#k8vee69|Y z^4}@|q&RM!1+gSWQd+F|1L?X8as;Yrqj?ikSnfR(KKf}W$ zH7Yj2tMPI~A|y~gm%GBNa&s>{&3LKjI`!6bFz*-HynnP(JUUZ3nwz5ki{_s!FfNrr z52IGATJg1z3Z3KgoqBO6fX0p~5y|l9b?9ryyu7@vly=1L?Pj+vpH~~=XBdb?j)FMw zk$^C1wJr`KQC$qtJ(+<006eJGK&STRN!-t34rY`YeZj^GmTS#0&@HH98Nd-zFD$l7 zcFtK4o2{TB-)76WAOISAFqRYwFkP5O%2*W=Hy^)5m8ZLq;+~~r=@BQ<20fH8*{_}gjaYddeM1oRg|uGG=bc*YGn_#d<8zh>%M=xz1WJ6WVUbWw z+sC|OghsP&yV%58M7?yfQ`!=XZuX!aZXM{DFzp@^U;sFd-JSk;_@^NMc&W??o!uHI z5<9)VE(VezZ#yC(sCW#7fyeOIc#Pa-!vr8eRgY28xxRwH=B`G^*C#PCg_%5wFln>i z$#~gpR&eS@saOLw4HQ8BE$|?uEQF<2#)HzrG!iyA)oBLH7}GBm%m55gxKzZ<&2%rN zRL-%dPHQu+Yh&+dcr--DA@0OBgK>;rUvMI0z(4@eoOR`UFwOi%hy}vyA!w0)>y!!avJ4cL26dWg314N(Y#C`kS zhY#-a#Bfwq_)!Q)rT8r}ebK^Io(TnAcwU+HMTR+%!`0Uky~41BzcV65Zkaa6bcM}l zCA|65-ZvI5EW*&1~7rGee*O&x>m$xOYdTR!AZ|B zJO8t~&z5VjYVPX^mXH8Cf^%exJPBQUAD-c>C6%V1eX+ECGz*3O$V4CAgD(`$2lcBk zLt!!Y6VOFy7$1W@Kp_qVuBe}=un5#ip+asB{yC*!aN`*~J$B6Sq-2tcL5@zV(wD1O zBK9o`yv0$uj6tEeq3TMu6e^JxmDD$4S?n)VUvy+;8dBb|ILdY`YS^uE zo|QVynqRF5?9xfxTMXci=Tk84hJdr}3u2oRiDc+hLz2!U(eQy`FYI=>6^6**NpBhf zOcPcIMD1-7Sc0l*;Vkc+I_0HsErIni&{`pdkFZ&MlOg7?XJk==f0-^I+2tT1Dk8~b z)M@4(w%Jn*y8&|Erhn!l#gX5F$yfqL+;+&mIYY3-SgKcI4oZCV#+wwEX)Pi&yk}B} z?=PpSmDCkZ#6-tVx~Y(T7-iTUr-jv+_gOMqAvLTa)>&a1nV5k2u!72k4oYA+?<=5& z2WA>8LcLS{>lrR*>9nKo<8WxAtNjZ8Zi6=fbB$+l{67gzD0!e=;XM7uW z40*yn?w(kK9jT94qw%u(#X(~tB1||e;}RPs5}blUB2M?`taQyIZFI0Y%JB{)L1)X5 z+)bpLc?jL6TFfYglrVdj4p{g#rw8YragbReVM%Cwi<&>>5RKX=%7<@PIyer|s(DD+ zZu1pu@WC;(*{JQH7R$P)gRNOB@{*tD(2#9|l+PK{a@;KJo+H07lZaBrWCjhP%}13n zw$H>!kFPJbSDK{?U%Q_&OdN9m&`x&1!}QxMBpuI%SD{etu*i}g{s818qS>pkplguI zhi{(MU*WzAf8kUIWyu#wFPy}JN`R4)VrJD#YC5B1iY2{KpJHtWDV0%ZnJM)sr2%&+ z)wJGFnz-43siZ5I8LO6tmm{eLE^^d{jObD(gv%+jj_P7jU~H>Kz@or!6dsewn3k_$ zqj9~_yx9QdPoIv}DhyL9s0w8=7U~CUd;vB?IWTODMGlYDm5iN6M75?Z=hX7FskZOk zy*oi)9e43@7ay{Vqi_!2#m!oP*E2%xW$9G7EkN%P{0-vsjFI*Q767N&0@JR--h$?= zmYvT;GsYy<{wCA0Gyo$H4O+Kzjt#m+#2Oq#S{#}7Mxv&{X9knFap1X0?zGl>^{=}> z`S1Vx?2X;mK791S8+-44w0q~zyMOwq_k%a&tKP@|2@m&vd+*Wb@Adxe=kRd%&5wKU zy!H6jt=_Aj;?Y{&gJkLDpnRrOt6{65HH0)YXR^d276?RINMp?d?B6x)MeHXVddNLM zn8MG8Af4<$2>hI%^w>^`Z8$(%f*3fo$F$@Y7)yZsfa!VZ<{@rT!756@)&d}#C0KZL z23y)90jcBj%(Fq3=HZ+sz22|>dGDPcJbdsL+Y;J+>+bG*_j`BHPjUDDo!#%ZsMVjxMo zY2!QS1Qq>UJ_GSYr?Sd%yWKQqwxzuZygtgVVB-99*GLkTXEiFhiSN zmEdJzxz29FZIN;!6q}oVs*qCSEA92r{+K8ncCX?zp35*GW>LQXXOv`Zkq_Z>9A@4P8K3%Q-@93EJCB$ z1Z5BcuK<9L&+|+Y4$ncnxh>;XlyR>?I&KD#S4fE;wF1eJJ2x-$$+ws zW0y_1n^L~qz>#ntlwI4-m z6x?HS??bh>Vt1gNYG0!wHo~=i*J0Hg!7$kktWKrTBifJfX#zD2HDhkn9%m8JazDU& zG}NVGNP?lx6lqrJn9=K4m$fIk$OK9IYPPPUkKHaMK>uL4#jKIxHkI5zs>_L9Mhy2j%c$&9tf&v;#G&omDahad#cpf`T0?;r?1UZW#1oZdLNA z6|#XtbsRmBk(f9HTd*P_m$bE2EeKjZeTr_m&;3O-#-85WKiYlc)rSv$#TXBI@1xi6@>idIzxT-}ncY8r zz?R-zG^jKhNhG{Sul`r>haa)mgaQl`-}F;FuoqITaI`|lWB~VPX`qnQG&Z(lY$I-c zXMOqn(#4H+p~Oar*AJwl55##C0OsvAIyl0VUg*3)^fd1>;=a&(^Cu7g`er@U7*P+` z(fd|NW{&t#4rJ8EiK3z;V;hvJ>!tXqqAF6djgG(UERv=`sQYY{TV1l9 z8+e=tb##HK_Z(|1omi=1*E-5;d6WFJT-8Ns)oiX`v4&Aj7H&iR4jr1JyX8v8gN4h4 zf|H?;c*$I&!*}{#Tof<>Hwa zVLiRDg8dHoK%Y9n(WOE0c-~SKmi!dG_ZSQcTd1NIDrNUlmotsJ7au1wa;?#7wn5_q zcHob__x`{~r+4nbpu@%(7>9sWz1w$9uPpX*p;94-dYC+OS^BSluB`}6lQ@QewHu;I z2EAT|I!aOjqZORU8+ZT!z1O!uw`+JM-X0!)Kp&@4V+U8T+W{t0VAk?_P~I+qx>#ok z`-CAJFl7J%d2GrzJ|IJ0&FDG<{iWLuxb_HY1VS#=Le#J(6rySE>i|`ub$BU0&!xN) zcg5%9BHXl_-K}k$BFpeM_*$)oMy)!`G?*ZdzDR&$ObD~ya)X@$!HgOiTsf$Gts$PU zC^fvvaHmlQ*o|g4ob<#rYka!EZjHV4mHTvB68mhmQL5E|m|+O(v|7NfE&{WDa|WCOOa2Mhluo+R8Fw z^%*s9k``(88N3_@5~aJ?^BV09%hQ5dDcAt^}uV= zSsacZ>#cQI~1D3)9dF~;!s=Js)<1OG?+Fc~A8k>@y{<`(wh~*&TH$)1mb(CB~wbVjj zRriwM(N>~|wVw94H@?^vng3huW~UkMPvRebjS&CyM1Fdl|K~8SIQ}!=_AK2!X&Zg? zzud{G=}7$76H{aT?=Y?-;SS7==;x6lUQefBG25hh)w@=@Q7YEEwN4f0&?3&Qq4eC= zi-5Xx9W?^noo!~(dX#12lQPS}Oo4_zjI$sPfwKv86VsbvKF2|CGz50&<`5Ndus1{xL3{Q>XYex#D z5=)oFHydU7te#0pZM6Y88rm)!d640LYS9cKpakdWmsF_MUI8J6d(&Q@#8!+;Mp~k zXLyktDV7q^Yc5~Y4$Nt)a6_GH%kuMFQHIi%s99Z*6DzKZ({2QX9R?d*Dg^0uNT)TT zx;(mtBz?Pc7I?)a2^3RIV^5(x_=fPc41J)(pV1_9Ob}u_x>aP*6?nJ`0*TlTvGk{i z?61ZRDv|yiiAu(u^j}yyd-2jzad~wi6PXUyVmzUOy3uo7tE)DUWk#J?Mpkf(4Fqw<9>7kd6<7<44 Xukkg$#@G1z5?}uhLL0}D0Js4Fkn~g^ diff --git a/pin-server-0.4.0.tar.gz b/pin-server-0.4.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..619999829c975c2cdbf5885605dff13b0cbde723 GIT binary patch literal 41798 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 BmK^{9 literal 0 HcmV?d00001 diff --git a/pin-server.spec b/pin-server.spec index cb97d4e..085eaec 100644 --- a/pin-server.spec +++ b/pin-server.spec @@ -1,6 +1,6 @@ Name: pin-server -Version: 0.3.0 -Release: 2 +Version: 0.4.0 +Release: 1 Summary: Pin (Plug-IN framework) server provides plugin APIs for compiler optimization developers to develop optimization pass. License: Apache 2.0 URL: https://gitee.com/openeuler/pin-server @@ -10,11 +10,6 @@ BuildRequires: gcc gcc-c++ cmake make pkgconfig grpc grpc-plugins grpc-devel pr BuildRequires: llvm-mlir llvm-mlir-static llvm-mlir-devel llvm-devel Requires: grpc protobuf -Patch1: 0001-Pin-server-Support-for-new-insertion-points-and-new-.patch -Patch2: 0002-Pin-server-support-LoopOp.patch -Patch3: 0003-Pin-server-Support-build-CFG-CondOp-CallOp-PhiOp-and.patch -Patch4: 0004-Pin-server-Support-Plugin-Pointer-Type.patch - %description Pin (Plug-IN framework) server provides plugin APIs for compiler optimization developers to develop optimization pass. @@ -32,11 +27,6 @@ A demo for pin-server %prep %setup -q -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 - mkdir -p _build cd _build %{cmake} .. -DCMAKE_INSTALL_PREFIX=%{_usr} -DCMAKE_INSTALL_LIBDIR=%{_libdir} -DMLIR_DIR=/usr/lib64/cmake/mlir -DLLVM_DIR=/usr/lib64/cmake/llvm @@ -62,6 +52,12 @@ cd _build %attr(0644,root,root) %{_libdir}/libpin_user.sha256 %changelog +* Tue Dec 20 2022 zhaowenyu <804544223@qq.com> - 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