From 817b4ac318f31e1c8414181ba96007f372e7008a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=81=95=E5=B1=B1?= Date: Wed, 8 Jan 2025 16:37:43 +0800 Subject: [PATCH 1/4] add comments on java example --- example/java/CallChainWithSignature.gdl | 44 +++++++++++++++---------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/example/java/CallChainWithSignature.gdl b/example/java/CallChainWithSignature.gdl index 1a03db36..a9fc58a1 100644 --- a/example/java/CallChainWithSignature.gdl +++ b/example/java/CallChainWithSignature.gdl @@ -15,18 +15,17 @@ fn isChecked(signature: string) -> bool { // You can view the signature, line number, and file location of each callable by outputting the following function: fn signature_name(signature: string, line: int, fileName: string) -> bool { - let (db = default_java_db()){ - for (callable in Callable(db)){ - if (signature = callable.getSignature() && fileName = callable.getLocation().getFile().getName() - && line = callable.getLocation().getStartLineNumber()) { - return true - } + for (callable in Callable(default_java_db())) { + if (signature = callable.getSignature() && + fileName = callable.getLocation().getFile().getName() && + line = callable.getLocation().getStartLineNumber()) { + return true } } } // Determine whether it is a callable corresponding to the function signature -fn checkCallable(c: Callable)-> bool { +fn checkCallable(c: Callable) -> bool { if (isChecked(c.getSignature())) { return true } @@ -35,7 +34,7 @@ fn checkCallable(c: Callable)-> bool { // Do an upward search fn getAncestorCallerEndWithLimit(c: Callable) -> *Callable { - // Get the calling function of the current functio + // Get the calling function of the current function yield c.getCaller() // The current node is multiple layers above, and recursive calls are required to obtain all calling functions for (tmp in c.getCaller()) { @@ -43,23 +42,35 @@ fn getAncestorCallerEndWithLimit(c: Callable) -> *Callable { } } -fn getAllLimitedCallable(c:Callable)->*Callable{ +fn getAllLimitedCallable(c: Callable) -> *Callable { yield c yield getAncestorCallerEndWithLimit(c) } // At the same time, output the class corresponding to callable -fn getCallGraph(callMethodName:string, callClassName: string, - calleeMethodName:string, calleeClassName: string) -> bool { - let (db = default_java_db()){ - for (callable in Callable(db)){ +fn getCallGraph(callMethodName: string, + callClassName: string, + calleeMethodName: string, + calleeClassName: string) -> bool { + let (db = default_java_db()) { + for (callable in Callable(db)) { if (checkCallable(callable)) { - for (call in getAllLimitedCallable(callable), callee in getAllLimitedCallable(callable)){ + for (call in getAllLimitedCallable(callable), callee in getAllLimitedCallable(callable)) { if (call != callee && callee in call.getCallee()) { + // Get the method corresponding to the callable + // But be aware that the callable is mixed with method and constructor + // So this call graph may not contain constructor for (callMethod in Method(db), calleeMethod in Method(db)) { if (callMethod.key_eq(call) && calleeMethod.key_eq(callee)) { - if (callMethodName = callMethod.getName() && callClassName = callMethod.getBelongedClass().getQualifiedName() && - calleeMethodName = callee.getName() && calleeClassName = calleeMethod.getBelongedClass().getQualifiedName()) { + if (callMethodName = callMethod.getName() && + callClassName = callMethod.getBelongedClass().getQualifiedName() && + calleeMethodName = callee.getName() && + // Also, method's getBelongedClass will get Class, + // but some of methods are belonged to interface. + // So this call graph may not contain methods in interfaces. + // If you want to get methods in interfaces, you can use the following code: + // calleeClassName = calleeMethod.getParent().getQualifiedName() + calleeClassName = calleeMethod.getBelongedClass().getQualifiedName()) { return true } } @@ -67,7 +78,6 @@ fn getCallGraph(callMethodName:string, callClassName: string, } } } - } } } From f128222762dd6f980c8f5bb936b467eafd6618cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=81=95=E5=B1=B1?= Date: Wed, 8 Jan 2025 17:06:53 +0800 Subject: [PATCH 2/4] add comments in inst combine pass --- .../godel-frontend/src/ir/inst_combine.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/godel-script/godel-frontend/src/ir/inst_combine.cpp b/godel-script/godel-frontend/src/ir/inst_combine.cpp index 693cc140..2e8b47ea 100644 --- a/godel-script/godel-frontend/src/ir/inst_combine.cpp +++ b/godel-script/godel-frontend/src/ir/inst_combine.cpp @@ -143,18 +143,26 @@ void inst_combine_pass::scan(souffle_rule_impl* b) { // for(const auto& i : variable_reference_graph) { const auto& name = i.first; - if (i.second.size()!=1) { + // if alias variables' count > 1, even if there's a circle, still skip it. + if (i.second.size() != 1) { continue; } + // alias variable's name const auto& to = i.second.begin()->first; if (!variable_reference_graph.count(to)) { continue; } - if (variable_reference_graph.at(to).size()!=1) { + // this variable's alias count should be 1 + if (variable_reference_graph.at(to).size() != 1) { continue; } + // get `to`'s alias variable's name, this name should be equal to `name` const auto& from = variable_reference_graph.at(to).begin()->first; - if (from==name && to.find("ssa_temp")==0 && from.find("ssa_temp")==0) { + // means there's a circle like this: + // `to` <--> `from`(aka `name`) + // after clear(), `to`'s alias count should be 0: + // `to` <--- `from`(aka `name`) + if (from == name && to.find("ssa_temp") == 0 && from.find("ssa_temp") == 0) { variable_reference_graph.at(to).clear(); } } From 9dcd1247583cc4f2810b96b165dd45216d4dd686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=81=95=E5=B1=B1?= Date: Thu, 9 Jan 2025 14:54:11 +0800 Subject: [PATCH 3/4] add inst combine rule for inst_aggr --- .../godel-frontend/src/ir/inst_combine.cpp | 9 +++++++++ godel-script/godel-frontend/src/ir/inst_combine.h | 1 + godel-script/godel-frontend/src/ir/lir.cpp | 14 +++++++++++++- godel-script/godel-frontend/src/ir/lir.h | 4 ++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/godel-script/godel-frontend/src/ir/inst_combine.cpp b/godel-script/godel-frontend/src/ir/inst_combine.cpp index 2e8b47ea..eabdc67e 100644 --- a/godel-script/godel-frontend/src/ir/inst_combine.cpp +++ b/godel-script/godel-frontend/src/ir/inst_combine.cpp @@ -241,6 +241,15 @@ void combine_worker::visit_binary(lir::binary* node) { } } +void combine_worker::visit_aggregator(lir::aggregator* node) { + const auto& tgt = node->get_target(); + if (is_single_ref_ssa_temp(tgt.content)) { + const auto& ref = get_single_ref(tgt.content); + node->get_mutable_target().content = ref.first; + ref.second->set_flag_eliminated(true); + } +} + void combine_worker::mark(souffle_rule_impl* b) { b->get_block()->accept(this); } diff --git a/godel-script/godel-frontend/src/ir/inst_combine.h b/godel-script/godel-frontend/src/ir/inst_combine.h index e14abc7c..b6b0c253 100644 --- a/godel-script/godel-frontend/src/ir/inst_combine.h +++ b/godel-script/godel-frontend/src/ir/inst_combine.h @@ -53,6 +53,7 @@ class combine_worker: public lir::inst_visitor { void visit_record(lir::record*) override; void visit_unary(lir::unary*) override; void visit_binary(lir::binary*) override; + void visit_aggregator(lir::aggregator*) override; public: combine_worker(const inst_combine_pass::ref_graph& g): vg(g) {} diff --git a/godel-script/godel-frontend/src/ir/lir.cpp b/godel-script/godel-frontend/src/ir/lir.cpp index 6c76ea7f..5e43efa6 100644 --- a/godel-script/godel-frontend/src/ir/lir.cpp +++ b/godel-script/godel-frontend/src/ir/lir.cpp @@ -359,7 +359,19 @@ void not_operand::dump(std::ostream& os, const std::string& indent) const { // only one statement in the block if (body->get_content().size()==1) { os << indent << "!("; - body->get_content()[0]->dump(os, ""); + switch(body->get_content()[0]->get_kind()) { + case inst_kind::inst_not: + case inst_kind::inst_and: + case inst_kind::inst_or: + case inst_kind::inst_aggr: + os << "\n"; + body->get_content()[0]->dump(os, indent + " "); + os << "\n" << indent; + break; + default: + body->get_content()[0]->dump(os, ""); + break; + } os << ")"; return; } diff --git a/godel-script/godel-frontend/src/ir/lir.h b/godel-script/godel-frontend/src/ir/lir.h index e69ec945..8cb2e8c5 100644 --- a/godel-script/godel-frontend/src/ir/lir.h +++ b/godel-script/godel-frontend/src/ir/lir.h @@ -666,6 +666,10 @@ class aggregator: public inst { void accept(inst_visitor* v) override { v->visit_aggregator(this); } + +public: + const auto& get_target() const { return destination; } + auto& get_mutable_target() { return destination; } }; } From 84645608cf3e53c492442d44b30311dc96d68b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=81=95=E5=B1=B1?= Date: Thu, 9 Jan 2025 15:02:29 +0800 Subject: [PATCH 4/4] default enable inst-combine to avoid ungrounded --- godel-script/godel-frontend/src/cli.cpp | 4 ++-- godel-script/godel-frontend/src/cli.h | 9 +++------ godel-script/godel-frontend/src/ir/pass_manager.cpp | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/godel-script/godel-frontend/src/cli.cpp b/godel-script/godel-frontend/src/cli.cpp index 078ec3dc..ba91f0fc 100644 --- a/godel-script/godel-frontend/src/cli.cpp +++ b/godel-script/godel-frontend/src/cli.cpp @@ -110,12 +110,12 @@ std::ostream& help(std::ostream& out) { << reset << "Enable souffle code generator for statement optimizer.\n" << green << " -Ol, --opt-let " << reset << "Enable souffle code generator let statement optimizer(not suggested).\n" - << green << " -Oim, --opt-ir-merge " - << reset << "Enable souffle inst combine pass.\n" << green << " -Osc, --opt-self-constraint " << reset << "Enable self data constraint optimizer in souffle code generator.\n" << green << " -Ojr, --opt-join-reorder " << reset << "Enable join reorder optimizer(experimental).\n" + << green << " --disable-inst-combine " + << reset << "Disable instruction combine pass.\n" << green << " --disable-remove-unused " << reset << "Disable unused method deletion pass.\n" << green << " --disable-do-schema-opt " diff --git a/godel-script/godel-frontend/src/cli.h b/godel-script/godel-frontend/src/cli.h index 8c071e0f..a39287d7 100644 --- a/godel-script/godel-frontend/src/cli.h +++ b/godel-script/godel-frontend/src/cli.h @@ -46,9 +46,9 @@ enum class option { /* optimization */ cli_enable_for_opt, // switch for optimization on cli_enable_let_opt, // switch let optimization on - cli_enable_ir_merge, // switch ir merge on cli_enable_self_constraint_opt, // switch self constraint optimization on cli_enable_join_reorder, // switch join reorder optimization on + cli_disable_inst_combine, // switch inst combine off cli_disable_remove_unused, // switch unused method deletion off cli_disable_do_schema_opt, // switch do schema optimization off cli_souffle_debug_dump, // switch souffle debug mode on @@ -121,12 +121,11 @@ const std::unordered_map options = { {"-Of", option::cli_enable_for_opt}, {"--opt-let", option::cli_enable_let_opt}, {"-Ol", option::cli_enable_let_opt}, - {"--opt-ir-merge", option::cli_enable_ir_merge}, - {"-Oim", option::cli_enable_ir_merge}, {"--opt-self-constraint", option::cli_enable_self_constraint_opt}, {"-Osc", option::cli_enable_self_constraint_opt}, {"--opt-join-reorder", option::cli_enable_join_reorder}, {"-Ojr", option::cli_enable_join_reorder}, + {"--disable-inst-combine", option::cli_disable_inst_combine}, {"--disable-remove-unused", option::cli_disable_remove_unused}, {"--disable-do-schema-opt", option::cli_disable_do_schema_opt}, {"--souffle-debug", option::cli_souffle_debug_dump}, @@ -142,11 +141,9 @@ const std::unordered_map options = { const std::unordered_map> multi_options = { {"-O1", {option::cli_enable_for_opt}}, {"-O2", {option::cli_enable_for_opt, - option::cli_enable_self_constraint_opt, - option::cli_enable_ir_merge}}, + option::cli_enable_self_constraint_opt}}, {"-O3", {option::cli_enable_for_opt, option::cli_enable_self_constraint_opt, - option::cli_enable_ir_merge, option::cli_enable_join_reorder}} }; diff --git a/godel-script/godel-frontend/src/ir/pass_manager.cpp b/godel-script/godel-frontend/src/ir/pass_manager.cpp index 08caec9d..46a68c49 100644 --- a/godel-script/godel-frontend/src/ir/pass_manager.cpp +++ b/godel-script/godel-frontend/src/ir/pass_manager.cpp @@ -28,7 +28,7 @@ void pass_manager::run(ir_context& ctx, const cli::configure& conf) { ordered_pass_list.push_back(new unused_remove_pass(ctx)); ordered_pass_list.push_back(new unused_type_alias_remove_pass(ctx)); } - if (conf.count(cli::option::cli_enable_ir_merge)) { + if (!conf.count(cli::option::cli_disable_inst_combine)) { ordered_pass_list.push_back(new inst_combine_pass(ctx)); } ordered_pass_list.push_back(new flatten_nested_block(ctx));