Commit 078a8fb5 authored by 张栋澈's avatar 张栋澈 🤡

[Lab4.2] Publish

parent 28a084f5
This diff is collapsed.
...@@ -106,3 +106,13 @@ C中,只能使用标准库中的`malloc`与`free`来进行内存分配,并 ...@@ -106,3 +106,13 @@ C中,只能使用标准库中的`malloc`与`free`来进行内存分配,并
1. `std::shared_ptr`: 引用计数智能指针,使用一个共享变量来记录指针管理的对象被引用了几次。当对象引用计数为0时,说明当前该对象不再有引用,并且进程也无法再通过其它方式来引用它,也就意味着可以回收内存,这相当于低级的垃圾回收策略。 1. `std::shared_ptr`: 引用计数智能指针,使用一个共享变量来记录指针管理的对象被引用了几次。当对象引用计数为0时,说明当前该对象不再有引用,并且进程也无法再通过其它方式来引用它,也就意味着可以回收内存,这相当于低级的垃圾回收策略。
2. `std::unique_ptr`: 表示所有权的智能指针,该指针要求它所管理的对象智能有一次引用,主要用于语义上不允许共享的对象(比如`llvm::Module`)。当引用计数为0时,它也会回收内存。 2. `std::unique_ptr`: 表示所有权的智能指针,该指针要求它所管理的对象智能有一次引用,主要用于语义上不允许共享的对象(比如`llvm::Module`)。当引用计数为0时,它也会回收内存。
## Debugging Seg Fault
Lab3/4 中,你可能会各种各样的段错误,不要害怕!clang 提供了一个工具来帮助我们解决内存泄漏。
```bash
cd build
cmake .. -DCMAKE_BUILD_TYPE=Asan
make
```
然后再次运行你的错误代码, Asan 会提供更详细的报错信息。
注:要更换到别的 build type (如Debug或Release)时需要显式指定,否则 cmake 会使用 cached 的版本。
# Lab4.2 实验报告
姓名 学号
## 实验要求
请按照自己的理解,写明本次实验需要做什么
## 实验难点
实验中遇到哪些挑战
## 实验设计
实现思路,相应代码,优化前后的IR对比(举一个例子)并辅以简单说明
### 思考题
1. 请简要分析你的算法复杂度
2. `std::shared_ptr`如果存在环形引用,则无法正确释放内存,你的 Expression 类是否存在 circular reference?
3. 尽管本次实验已经写了很多代码,但是在算法上和工程上仍然可以对 GVN 进行改进,请简述你的 GVN 实现可以改进的地方
## 实验总结
此次实验有什么收获
## 实验反馈(可选 不会评分)
对本次实验的建议
...@@ -55,8 +55,8 @@ class Instruction : public User, public llvm::ilist_node<Instruction> { ...@@ -55,8 +55,8 @@ class Instruction : public User, public llvm::ilist_node<Instruction> {
Module *get_module(); Module *get_module();
OpID get_instr_type() const { return op_id_; } OpID get_instr_type() const { return op_id_; }
std::string get_instr_op_name() { static std::string get_instr_op_name(OpID id) {
switch (op_id_) { switch (id) {
case ret: return "ret"; break; case ret: return "ret"; break;
case br: return "br"; break; case br: return "br"; break;
case add: return "add"; break; case add: return "add"; break;
...@@ -82,6 +82,7 @@ class Instruction : public User, public llvm::ilist_node<Instruction> { ...@@ -82,6 +82,7 @@ class Instruction : public User, public llvm::ilist_node<Instruction> {
default: return ""; break; default: return ""; break;
} }
} }
std::string get_instr_op_name() { return get_instr_op_name(op_id_); }
bool is_void() { bool is_void() {
return ((op_id_ == ret) || (op_id_ == br) || (op_id_ == store) || return ((op_id_ == ret) || (op_id_ == br) || (op_id_ == store) ||
......
#ifndef SYSYC_VALUE_H #ifndef SYSYC_VALUE_H
#define SYSYC_VALUE_H #define SYSYC_VALUE_H
#include <functional>
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <string> #include <string>
class Type; class Type;
class Value; class Value;
class User;
struct Use { struct Use {
Value *val_; Value *val_;
...@@ -35,6 +37,8 @@ class Value { ...@@ -35,6 +37,8 @@ class Value {
std::string get_name() const; std::string get_name() const;
void replace_all_use_with(Value *new_val); void replace_all_use_with(Value *new_val);
/// replace `value` with `new_val` when the user of value satisfies predicate `pred`
void replace_use_with_when(Value *new_val, std::function<bool(User *)> pred);
void remove_use(Value *val); void remove_use(Value *val);
virtual std::string print() = 0; virtual std::string print() = 0;
......
#pragma once
#include "FuncInfo.h"
#include "Function.h"
#include "Instruction.h"
#include "PassManager.hpp"
#include "logging.hpp"
/**
* 死代码消除:参见 https://www.clear.rice.edu/comp512/Lectures/10Dead-Clean-SCCP.pdf
**/
class DeadCode : public Pass {
public:
DeadCode(Module *m) : Pass(m), func_info(std::make_shared<FuncInfo>(m)) {}
// 处理流程:两趟处理,mark 标记有用变量,sweep 删除无用指令
void run() {
bool changed{};
func_info->run();
do {
changed = false;
for (auto &F : m_->get_functions()) {
auto func = &F;
mark(func);
changed |= sweep(func);
}
} while (changed);
LOG_INFO << "dead code pass erased " << ins_count << " instructions";
}
private:
std::shared_ptr<FuncInfo> func_info;
void mark(Function *func) {
work_list.clear();
marked.clear();
for (auto &bb : func->get_basic_blocks()) {
for (auto &ins : bb.get_instructions()) {
if (is_critical(&ins)) {
marked[&ins] = true;
work_list.push_back(&ins);
}
}
}
while (work_list.empty() == false) {
auto now = work_list.front();
work_list.pop_front();
mark(now);
}
}
void mark(Instruction *ins) {
for (auto op : ins->get_operands()) {
auto def = dynamic_cast<Instruction *>(op);
if (def == nullptr)
continue;
if (marked[def])
continue;
if (def->get_function() != ins->get_function())
continue;
marked[def] = true;
work_list.push_back(def);
}
}
bool sweep(Function *func) {
std::unordered_set<Instruction *> wait_del{};
for (auto &bb : func->get_basic_blocks()) {
for (auto it = bb.get_instructions().begin(); it != bb.get_instructions().end();) {
if (marked[&*it]) {
++it;
continue;
} else {
auto tmp = &*it;
wait_del.insert(tmp);
it++;
}
}
}
for (auto inst : wait_del)
inst->remove_use_of_ops();
for (auto inst : wait_del)
inst->get_parent()->get_instructions().erase(inst);
ins_count += wait_del.size();
return not wait_del.empty(); // changed
}
bool is_critical(Instruction *ins) {
// 对纯函数的无用调用也可以在删除之列
if (ins->is_call()) {
auto call_inst = dynamic_cast<CallInst *>(ins);
auto callee = dynamic_cast<Function *>(call_inst->get_operand(0));
if (func_info->is_pure_function(callee))
return false;
return true;
}
if (ins->is_br() || ins->is_ret())
return true;
if (ins->is_store())
return true;
return false;
}
// 用以衡量死代码消除的性能
int ins_count{0};
std::deque<Instruction *> work_list{};
std::unordered_map<Instruction *, bool> marked{};
};
#pragma once
#include "Function.h"
#include "PassManager.hpp"
#include "logging.hpp"
#include <deque>
#include <unordered_map>
#include <unordered_set>
/**
* 计算哪些函数是纯函数
* WARN: 假定所有函数都是纯函数,除非他写入了全局变量、修改了传入的数组、或者直接间接调用了非纯函数
*/
class FuncInfo : public Pass {
public:
FuncInfo(Module *m) : Pass(m) {}
void run() {
for (auto &f : m_->get_functions()) {
auto func = &f;
trivial_mark(func);
if (not is_pure[func])
worklist.push_back(func);
}
while (worklist.empty() == false) {
auto now = worklist.front();
worklist.pop_front();
process(now);
}
log();
}
bool is_pure_function(Function *func) const {
// exit_if(is_pure.find(func) == is_pure.end(), ERROR_IN_PURE_FUNCTION_ANALYSIS);
return is_pure.at(func);
}
void log() {
for (auto it : is_pure) {
LOG_INFO << it.first->get_name() << " is pure? " << it.second;
}
}
private:
// 有 store 操作的函数非纯函数来处理
void trivial_mark(Function *func) {
if (func->is_declaration() or func->get_name() == "main") {
is_pure[func] = false;
return;
}
// 只要传入数组,都作为非纯函数处理
for (auto it = func->get_function_type()->param_begin(); it != func->get_function_type()->param_end(); ++it) {
auto arg_type = *it;
if (arg_type->is_integer_type() == false and arg_type->is_float_type() == false) {
is_pure[func] = false;
return;
}
}
for (auto &bb : func->get_basic_blocks())
for (auto &inst : bb.get_instructions()) {
if (is_side_effect_inst(&inst)) {
is_pure[func] = false;
return;
}
}
is_pure[func] = true;
}
void process(Function *func) {
for (auto &use : func->get_use_list()) {
LOG_INFO << use.val_->print() << " uses func: " << func->get_name();
if (auto inst = dynamic_cast<Instruction *>(use.val_)) {
auto func = (inst->get_parent()->get_parent());
if (is_pure[func]) {
is_pure[func] = false;
worklist.push_back(func);
}
} else
LOG_WARNING << "Value besides instruction uses a function";
}
}
// 对局部变量进行 store 没有副作用
bool is_side_effect_inst(Instruction *inst) {
if (inst->is_store()) {
if (is_local_store(dynamic_cast<StoreInst *>(inst)))
return false;
return true;
}
if (inst->is_load()) {
if (is_local_load(dynamic_cast<LoadInst *>(inst)))
return false;
return true;
}
// call 指令的副作用会在后续 bfs 中计算
return false;
}
bool is_local_load(LoadInst *inst) {
auto addr = dynamic_cast<Instruction *>(get_first_addr(inst->get_operand(0)));
if (addr and addr->is_alloca())
return true;
return false;
}
bool is_local_store(StoreInst *inst) {
auto addr = dynamic_cast<Instruction *>(get_first_addr(inst->get_lval()));
if (addr and addr->is_alloca())
return true;
return false;
}
Value *get_first_addr(Value *val) {
if (auto inst = dynamic_cast<Instruction *>(val)) {
if (inst->is_alloca())
return inst;
if (inst->is_gep())
return get_first_addr(inst->get_operand(0));
if (inst->is_load())
return val;
LOG_WARNING << "FuncInfo: try to determine addr in operands";
for (auto op : inst->get_operands()) {
if (op->get_type()->is_pointer_type())
return get_first_addr(op);
}
}
return val;
}
std::deque<Function *> worklist;
std::unordered_map<Function *, bool> is_pure;
};
#pragma once
#include "BasicBlock.h"
#include "Constant.h"
#include "DeadCode.h"
#include "FuncInfo.h"
#include "Function.h"
#include "Instruction.h"
#include "Module.h"
#include "PassManager.hpp"
#include "Value.h"
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>
namespace GVNExpression {
// fold the constant value
class ConstFolder {
public:
ConstFolder(Module *m) : module_(m) {}
Constant *compute(Instruction *instr, Constant *value1, Constant *value2);
Constant *compute(Instruction *instr, Constant *value1);
private:
Module *module_;
};
/**
* for constructor of class derived from `Expression`, we make it public
* because `std::make_shared` needs the constructor to be publicly available,
* but you should call the static factory method `create` instead the constructor itself to get the desired data
*/
class Expression {
public:
// TODO: you need to extend expression types according to testcases
enum gvn_expr_t { e_constant, e_bin, e_phi };
Expression(gvn_expr_t t) : expr_type(t) {}
virtual ~Expression() = default;
virtual std::string print() = 0;
gvn_expr_t get_expr_type() const { return expr_type; }
private:
gvn_expr_t expr_type;
};
bool operator==(const std::shared_ptr<Expression> &lhs, const std::shared_ptr<Expression> &rhs);
bool operator==(const GVNExpression::Expression &lhs, const GVNExpression::Expression &rhs);
class ConstantExpression : public Expression {
public:
static std::shared_ptr<ConstantExpression> create(Constant *c) { return std::make_shared<ConstantExpression>(c); }
virtual std::string print() { return c_->print(); }
// we leverage the fact that constants in lightIR have unique addresses
bool equiv(const ConstantExpression *other) const { return c_ == other->c_; }
ConstantExpression(Constant *c) : Expression(e_constant), c_(c) {}
private:
Constant *c_;
};
// arithmetic expression
class BinaryExpression : public Expression {
public:
static std::shared_ptr<BinaryExpression> create(Instruction::OpID op,
std::shared_ptr<Expression> lhs,
std::shared_ptr<Expression> rhs) {
return std::make_shared<BinaryExpression>(op, lhs, rhs);
}
virtual std::string print() {
return "(" + Instruction::get_instr_op_name(op_) + " " + lhs_->print() + " " + rhs_->print() + ")";
}
bool equiv(const BinaryExpression *other) const {
if (op_ == other->op_ and *lhs_ == *other->lhs_ and *rhs_ == *other->rhs_)
return true;
else
return false;
}
BinaryExpression(Instruction::OpID op, std::shared_ptr<Expression> lhs, std::shared_ptr<Expression> rhs)
: Expression(e_bin), op_(op), lhs_(lhs), rhs_(rhs) {}
private:
Instruction::OpID op_;
std::shared_ptr<Expression> lhs_, rhs_;
};
class PhiExpression : public Expression {
public:
static std::shared_ptr<PhiExpression> create(std::shared_ptr<Expression> lhs, std::shared_ptr<Expression> rhs) {
return std::make_shared<PhiExpression>(lhs, rhs);
}
virtual std::string print() { return "(phi " + lhs_->print() + " " + rhs_->print() + ")"; }
bool equiv(const PhiExpression *other) const {
if (*lhs_ == *other->lhs_ and *rhs_ == *other->rhs_)
return true;
else
return false;
}
PhiExpression(std::shared_ptr<Expression> lhs, std::shared_ptr<Expression> rhs)
: Expression(e_phi), lhs_(lhs), rhs_(rhs) {}
private:
std::shared_ptr<Expression> lhs_, rhs_;
};
} // namespace GVNExpression
/**
* Congruence class in each partitions
* note: for constant propagation, you might need to add other fields
* and for load/store redundancy detection, you most certainly need to modify the class
*/
struct CongruenceClass {
size_t index_;
// representative of the congruence class, used to replace all the members (except itself) when analysis is done
Value *leader_;
// value expression in congruence class
std::shared_ptr<GVNExpression::Expression> value_expr_;
// value φ-function is an annotation of the congruence class
std::shared_ptr<GVNExpression::PhiExpression> value_phi_;
// equivalent variables in one congruence class
std::set<Value *> members_;
CongruenceClass(size_t index) : index_(index), leader_{}, value_expr_{}, value_phi_{}, members_{} {}
bool operator<(const CongruenceClass &other) const { return this->index_ < other.index_; }
bool operator==(const CongruenceClass &other) const;
};
namespace std {
template <>
// overload std::less for std::shared_ptr<CongruenceClass>, i.e. how to sort the congruence classes
struct less<std::shared_ptr<CongruenceClass>> {
bool operator()(const std::shared_ptr<CongruenceClass> &a, const std::shared_ptr<CongruenceClass> &b) const {
// nullptrs should never appear in partitions, so we just dereference it
return *a < *b;
}
};
} // namespace std
class GVN : public Pass {
public:
using partitions = std::set<std::shared_ptr<CongruenceClass>>;
GVN(Module *m, bool dump_json) : Pass(m), dump_json_(dump_json) {}
// pass start
void run() override;
// init for pass metadata;
void initPerFunction();
// fill the following functions according to Pseudocode, **you might need to add more arguments**
void detectEquivalences();
partitions join(const partitions &P1, const partitions &P2);
std::shared_ptr<CongruenceClass> intersect(std::shared_ptr<CongruenceClass>, std::shared_ptr<CongruenceClass>);
partitions transferFunction(Instruction *x, Value *e, partitions pin);
std::shared_ptr<GVNExpression::PhiExpression> valuePhiFunc(std::shared_ptr<GVNExpression::Expression>,
const partitions &);
std::shared_ptr<GVNExpression::Expression> valueExpr(Instruction *instr);
std::shared_ptr<GVNExpression::Expression> getVN(const partitions &pout,
std::shared_ptr<GVNExpression::Expression> ve);
// replace cc members with leader
void replace_cc_members();
// note: be careful when to use copy constructor or clone
partitions clone(const partitions &p);
// create congruence class helper
std::shared_ptr<CongruenceClass> createCongruenceClass(size_t index = 0) {
return std::make_shared<CongruenceClass>(index);
}
private:
bool dump_json_;
std::uint64_t next_value_number_ = 1;
Function *func_;
std::map<BasicBlock *, partitions> pin_, pout_;
std::unique_ptr<FuncInfo> func_info_;
std::unique_ptr<GVNExpression::ConstFolder> folder_;
std::unique_ptr<DeadCode> dce_;
};
bool operator==(const GVN::partitions &p1, const GVN::partitions &p2);
...@@ -3,4 +3,4 @@ add_subdirectory(common) ...@@ -3,4 +3,4 @@ add_subdirectory(common)
add_subdirectory(io) add_subdirectory(io)
add_subdirectory(lightir) add_subdirectory(lightir)
add_subdirectory(cminusfc) add_subdirectory(cminusfc)
add_subdirectory(optimization) add_subdirectory(optimization)
\ No newline at end of file
#include "Dominators.h" #include "Dominators.h"
#include "GVN.h"
#include "Mem2Reg.hpp" #include "Mem2Reg.hpp"
#include "PassManager.hpp" #include "PassManager.hpp"
#include "cminusf_builder.hpp" #include "cminusf_builder.hpp"
...@@ -11,7 +12,8 @@ ...@@ -11,7 +12,8 @@
using namespace std::literals::string_literals; using namespace std::literals::string_literals;
void print_help(std::string exe_name) { void print_help(std::string exe_name) {
std::cout << "Usage: " << exe_name << " [ -h | --help ] [ -o <target-file> ] [ -emit-llvm ] [-mem2reg] <input-file>" std::cout << "Usage: " << exe_name
<< " [ -h | --help ] [ -o <target-file> ] [ -emit-llvm ] [-mem2reg] [-gvn] [-dump-json] <input-file>"
<< std::endl; << std::endl;
} }
...@@ -20,6 +22,8 @@ int main(int argc, char **argv) { ...@@ -20,6 +22,8 @@ int main(int argc, char **argv) {
std::string input_path; std::string input_path;
bool mem2reg = false; bool mem2reg = false;
bool gvn = false;
bool dump_json = false;
bool emit = false; bool emit = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
...@@ -38,6 +42,10 @@ int main(int argc, char **argv) { ...@@ -38,6 +42,10 @@ int main(int argc, char **argv) {
emit = true; emit = true;
} else if (argv[i] == "-mem2reg"s) { } else if (argv[i] == "-mem2reg"s) {
mem2reg = true; mem2reg = true;
} else if (argv[i] == "-gvn"s) {
gvn = true;
} else if (argv[i] == "-dump-json"s) {
dump_json = true;
} else { } else {
if (input_path.empty()) { if (input_path.empty()) {
input_path = argv[i]; input_path = argv[i];
...@@ -47,6 +55,8 @@ int main(int argc, char **argv) { ...@@ -47,6 +55,8 @@ int main(int argc, char **argv) {
} }
} }
} }
if (gvn and not mem2reg)
LOG_WARNING << "Enabling GVN without mem2reg";
if (input_path.empty()) { if (input_path.empty()) {
print_help(argv[0]); print_help(argv[0]);
return 0; return 0;
...@@ -77,12 +87,15 @@ int main(int argc, char **argv) { ...@@ -77,12 +87,15 @@ int main(int argc, char **argv) {
auto m = builder.getModule(); auto m = builder.getModule();
m->set_print_name(); // m->set_print_name();
PassManager PM(m.get()); PassManager PM(m.get());
if (mem2reg) { if (mem2reg) {
PM.add_pass<Mem2Reg>(emit); PM.add_pass<Mem2Reg>(emit);
} }
if (gvn)
PM.add_pass<GVN>(emit, dump_json);
PM.run(); PM.run();
auto IR = m->print(); auto IR = m->print();
...@@ -95,11 +108,13 @@ int main(int argc, char **argv) { ...@@ -95,11 +108,13 @@ int main(int argc, char **argv) {
output_stream << IR; output_stream << IR;
output_stream.close(); output_stream.close();
if (!emit) { if (!emit) {
std::string lib_path = argv[0]; std::string lib_path = " -L"s + argv[0];
auto idx = lib_path.rfind('/'); auto idx = lib_path.rfind('/');
if (idx != std::string::npos) if (idx != std::string::npos)
lib_path.erase(lib_path.rfind('/')); lib_path.erase(idx);
auto cmd_str = "clang -O0 -w "s + target_path + ".ll -o " + target_path + " -L" + lib_path + " -lcminus_io"; else
lib_path.clear();
auto cmd_str = "clang -O0 -w -no-pie "s + target_path + ".ll -o " + target_path + lib_path + " -lcminus_io";
int re_code0 = std::system(cmd_str.c_str()); int re_code0 = std::system(cmd_str.c_str());
cmd_str = "rm "s + target_path + ".ll"; cmd_str = "rm "s + target_path + ".ll";
int re_code1 = std::system(cmd_str.c_str()); int re_code1 = std::system(cmd_str.c_str());
...@@ -108,5 +123,6 @@ int main(int argc, char **argv) { ...@@ -108,5 +123,6 @@ int main(int argc, char **argv) {
else else
return 1; return 1;
} }
return 0; return 0;
} }
...@@ -24,3 +24,17 @@ void Value::remove_use(Value *val) { ...@@ -24,3 +24,17 @@ void Value::remove_use(Value *val) {
auto is_val = [val](const Use &use) { return use.val_ == val; }; auto is_val = [val](const Use &use) { return use.val_ == val; };
use_list_.remove_if(is_val); use_list_.remove_if(is_val);
} }
void Value::replace_use_with_when(Value *new_val, std::function<bool(User *)> pred) {
for (auto it = use_list_.begin(); it != use_list_.end();) {
auto use = *it;
auto val = dynamic_cast<User *>(use.val_);
assert(val && "new_val is not a user");
if (not pred(val)) {
++it;
continue;
}
val->set_operand(use.arg_no_, new_val);
it = use_list_.erase(it);
}
}
...@@ -2,4 +2,5 @@ add_library( ...@@ -2,4 +2,5 @@ add_library(
OP_lib STATIC OP_lib STATIC
Dominators.cpp Dominators.cpp
Mem2Reg.cpp Mem2Reg.cpp
GVN.cpp
) )
This diff is collapsed.
This diff is collapsed.
/* c and d are redundant, and also check for constant propagation */
int main(void) {
int a;
int b;
int c;
int d;
if (input() > input()) {
a = 33 + 33;
b = 44 + 44;
c = a + b;
} else {
a = 55 + 55;
b = 66 + 66;
c = a + b;
}
output(c);
d = a + b;
output(d);
}
[
{
"function": "main",
"pout": {
"label_entry": [
[
"%op0",
],
[
"%op1",
],
[
"%op2",
],
[
"%op3",
],
[
"%op4",
],
],
"label5": [
[
"%op0",
],
[
"%op1",
],
[
"%op2",
],
[
"%op3",
],
[
"%op4",
],
[
"%op6",
"%op12",
],
[
"%op7",
"%op11",
],
[
"%op8",
"%op10",
],
],
"label9": [
[
"%op0",
],
[
"%op1",
],
[
"%op2",
],
[
"%op3",
],
[
"%op4",
],
[
"%op12",
],
[
"%op11",
],
[
"%op13",
"%op10",
],
],
"label14": [
[
"%op0",
],
[
"%op1",
],
[
"%op2",
],
[
"%op3",
],
[
"%op4",
],
[
"%op15",
"%op12",
],
[
"%op16",
"%op11",
],
[
"%op17",
"%op10",
],
],
}
},
]
\ No newline at end of file
/* c and d are redundant, e and f are not redundant */
int main(void) {
int i;
int j;
int a;
int b;
int c;
int d;
int e;
int f;
a = 0;
b = 0;
c = 0;
d = 0;
e = 0;
f = 0;
i = 1;
while (i < 10) {
j = 1;
a = input();
b = input();
c = a + b;
while (j < 10) {
i = i + j;
j = i + j;
c = a + b;
}
d = a + b;
i = i + 1;
e = c + d;
output(c);
output(d);
}
f = c + d;
output(e);
output(f);
return 0;
}
[
{
"function": "main",
"pout": {
"label_entry": [
[
0,
"%op3",
"%op2",
"%op1",
],
[
1,
"%op7",
],
],
"label0": [
[
"%op3",
"%op2",
],
[
"%op1",
],
[
"%op7",
],
[
"%op8",
],
[
"%op9",
],
[
"%op10",
],
],
"label11": [
[
"%op3",
"%op2",
],
[
"%op1",
],
[
"%op20",
"%op7",
],
[
"%op8",
],
[
"%op9",
],
[
"%op10",
],
[
"%op12",
],
[
"%op13",
],
[
"%op14",
"%op18",
],
[
1,
"%op19",
],
],
"label15": [
[
"%op3",
"%op2",
],
[
"%op1",
],
[
"%op7",
],
[
"%op8",
],
[
"%op9",
],
[
"%op10",
],
[
"%op16",
],
],
"label17": [
[
"%op12",
],
[
"%op13",
],
[
"%op3",
"%op2",
],
[
"%op1",
],
[
"%op8",
],
[
"%op9",
],
[
"%op10",
],
[
"%op7",
],
[
"%op20",
],
[
"%op14",
"%op18",
],
[
"%op19",
],
[
"%op21",
],
[
"%op22",
],
[
"%op23",
],
],
"label24": [
[
"%op12",
],
[
"%op13",
],
[
"%op3",
"%op2",
],
[
"%op1",
],
[
"%op8",
],
[
"%op9",
],
[
"%op10",
],
[
"%op7",
],
[
"%op14",
"%op27",
"%op18",
],
[
"%op21",
],
[
"%op22",
],
[
"%op23",
],
[
"%op25",
],
[
"%op26",
"%op19",
],
[
"%op20",
],
],
"label28": [
[
"%op12",
],
[
"%op13",
],
[
"%op8",
],
[
"%op9",
],
[
"%op10",
],
[
"%op20",
],
[
"%op14",
"%op29",
"%op3",
"%op18",
"%op2",
],
[
"%op19",
],
[
"%op21",
],
[
"%op22",
],
[
"%op23",
],
[
"%op30",
"%op7",
],
[
"%op31",
"%op1",
],
],
}
},
]
\ No newline at end of file
/* `max` is pure, can be detected using FuncInfo */
int max(int a, int b) {
if (a > b)
return a;
return b;
}
int a[10000];
int b[10000];
void inputarray(int a[], int n) {
int i;
i = 0;
while (i < n) {
a[i] = input();
i = i + 1;
}
}
int main(void) {
int i;
int n;
n = input();
inputarray(a, n);
inputarray(b, n);
i = 0;
while (i < n) {
int ai;
int bi;
/* `gep a i` and `max(ai,bi)` are redundant */
ai = a[i];
bi = b[i];
a[i] = max(ai, bi) * max(ai, bi);
i = i + 1;
}
i = 0;
while (i < n) {
output(a[i]);
i = i + 1;
}
}
\ No newline at end of file
This diff is collapsed.
/* check GVN on one-block input */
int main(void) {
int a;
int b;
/* we provide a pure function analysis,
input is not side-effect free, so multiple calls to input are considered different */
a = input();
b = input();
output(a + b);
output(a + b);
return 0;
}
[{
"function": "main",
"pout": {"label_entry": [["%op0", ], ["%op1", ], ["%op2", "%op3", ], ],
}},]
\ No newline at end of file
declare i32 @input()
declare void @output(i32)
declare void @outputFloat(float)
declare void @neg_idx_except()
define void @main() {
label_entry:
%op0 = call i32 @input()
br label %label1
label1: ; preds = %label_entry, %label11
%op2 = phi i32 [ 0, %label_entry ], [ 711082625, %label11 ]
%op7 = phi i32 [ 0, %label_entry ], [ %op37, %label11 ]
%op8 = icmp slt i32 %op7, %op0
%op9 = zext i1 %op8 to i32
%op10 = icmp ne i32 %op9, 0
br i1 %op10, label %label11, label %label38
label11: ; preds = %label1
%op37 = add i32 %op7, 1
br label %label1
label38: ; preds = %label1
call void @output(i32 %op2)
ret void
}
10000000
30
2
5
4
25
8
125
16
625
32
3125
2
5
4
25
8
125
16
625
32
3125
2
5
4
25
8
125
16
625
32
3125
; ModuleID = 'cminus'
source_filename = "./test.cminus"
@matrix = global [20000000 x i32] zeroinitializer
@ad = global [100000 x i32] zeroinitializer
@len = global i32 zeroinitializer
declare i32 @input()
declare void @output(i32)
declare void @outputFloat(float)
declare void @neg_idx_except()
define void @readarray() {
label_entry:
br label %label0
label0: ; preds = %label_entry, %label11
%op1 = phi i32 [ 0, %label_entry ], [ %op13, %label11 ]
%op2 = load i32, i32* @len
%op3 = icmp slt i32 %op1, %op2
%op4 = zext i1 %op3 to i32
%op5 = icmp ne i32 %op4, 0
br i1 %op5, label %label6, label %label9
label6: ; preds = %label0
%op7 = call i32 @input()
%op8 = icmp slt i32 %op1, 0
br i1 %op8, label %label10, label %label11
label9: ; preds = %label0
ret void
label10: ; preds = %label6
call void @neg_idx_except()
ret void
label11: ; preds = %label6
%op12 = getelementptr [100000 x i32], [100000 x i32]* @ad, i32 0, i32 %op1
store i32 %op7, i32* %op12
%op13 = add i32 %op1, 1
br label %label0
}
define i32 @transpose(i32 %arg0, i32* %arg1, i32 %arg2) {
label_entry:
%op4 = sdiv i32 %arg0, %arg2
br label %label5
label5: ; preds = %label_entry, %label25
%op8 = phi i32 [ 0, %label_entry ], [ %op26, %label25 ]
%op9 = icmp slt i32 %op8, %op4
%op10 = zext i1 %op9 to i32
%op11 = icmp ne i32 %op10, 0
br i1 %op11, label %label12, label %label13
label12: ; preds = %label5
br label %label15
label13: ; preds = %label5
ret i32 -1
label15: ; preds = %label12, %label29
%op17 = phi i32 [ 0, %label12 ], [ %op31, %label29 ]
%op18 = icmp slt i32 %op17, %arg2
%op19 = zext i1 %op18 to i32
%op20 = icmp ne i32 %op19, 0
br i1 %op20, label %label21, label %label25
label21: ; preds = %label15
%op22 = icmp slt i32 %op8, %op17
%op23 = zext i1 %op22 to i32
%op24 = icmp ne i32 %op23, 0
br i1 %op24, label %label27, label %label32
label25: ; preds = %label15
%op26 = add i32 %op8, 1
br label %label5
label27: ; preds = %label21
%op28 = add i32 %op17, 1
br label %label29
label29: ; preds = %label27, %label57
%op31 = phi i32 [ %op28, %label27 ], [ %op59, %label57 ]
br label %label15
label32: ; preds = %label21
%op33 = mul i32 %op8, %arg2
%op34 = add i32 %op33, %op17
%op35 = icmp slt i32 %op34, 0
br i1 %op35, label %label36, label %label37
label36: ; preds = %label32
call void @neg_idx_except()
ret i32 0
label37: ; preds = %label32
%op38 = getelementptr i32, i32* %arg1, i32 %op34
%op39 = load i32, i32* %op38
br i1 %op35, label %label43, label %label44
label43: ; preds = %label37
call void @neg_idx_except()
ret i32 0
label44: ; preds = %label37
%op46 = load i32, i32* %op38
%op47 = mul i32 %op17, %op4
%op48 = add i32 %op47, %op8
%op49 = icmp slt i32 %op48, 0
br i1 %op49, label %label50, label %label51
label50: ; preds = %label44
call void @neg_idx_except()
ret i32 0
label51: ; preds = %label44
%op52 = getelementptr i32, i32* %arg1, i32 %op48
store i32 %op46, i32* %op52
br i1 %op35, label %label56, label %label57
label56: ; preds = %label51
call void @neg_idx_except()
ret i32 0
label57: ; preds = %label51
store i32 %op39, i32* %op38
%op59 = add i32 %op17, 1
br label %label29
}
define i32 @main() {
label_entry:
%op0 = call i32 @input()
%op1 = call i32 @input()
store i32 %op1, i32* @len
call void @readarray()
br label %label2
label2: ; preds = %label_entry, %label11
%op3 = phi i32 [ 0, %label_entry ], [ %op13, %label11 ]
%op4 = icmp slt i32 %op3, %op0
%op5 = zext i1 %op4 to i32
%op6 = icmp ne i32 %op5, 0
br i1 %op6, label %label7, label %label9
label7: ; preds = %label2
%op8 = icmp slt i32 %op3, 0
br i1 %op8, label %label10, label %label11
label9: ; preds = %label2
br label %label14
label10: ; preds = %label7
call void @neg_idx_except()
ret i32 0
label11: ; preds = %label7
%op12 = getelementptr [20000000 x i32], [20000000 x i32]* @matrix, i32 0, i32 %op3
store i32 %op3, i32* %op12
%op13 = add i32 %op3, 1
br label %label2
label14: ; preds = %label9, %label25
%op15 = phi i32 [ 0, %label9 ], [ %op29, %label25 ]
%op16 = load i32, i32* @len
%op17 = icmp slt i32 %op15, %op16
%op18 = zext i1 %op17 to i32
%op19 = icmp ne i32 %op18, 0
br i1 %op19, label %label20, label %label23
label20: ; preds = %label14
%op21 = getelementptr [20000000 x i32], [20000000 x i32]* @matrix, i32 0, i32 0
%op22 = icmp slt i32 %op15, 0
br i1 %op22, label %label24, label %label25
label23: ; preds = %label14
br label %label30
label24: ; preds = %label20
call void @neg_idx_except()
ret i32 0
label25: ; preds = %label20
%op26 = getelementptr [100000 x i32], [100000 x i32]* @ad, i32 0, i32 %op15
%op27 = load i32, i32* %op26
%op28 = call i32 @transpose(i32 %op0, i32* %op21, i32 %op27)
%op29 = add i32 %op15, 1
br label %label14
label30: ; preds = %label23, %label45
%op31 = phi i32 [ 0, %label23 ], [ %op49, %label45 ]
%op32 = phi i32 [ 0, %label23 ], [ %op50, %label45 ]
%op33 = load i32, i32* @len
%op34 = icmp slt i32 %op32, %op33
%op35 = zext i1 %op34 to i32
%op36 = icmp ne i32 %op35, 0
br i1 %op36, label %label37, label %label40
label37: ; preds = %label30
%op38 = mul i32 %op32, %op32
%op39 = icmp slt i32 %op32, 0
br i1 %op39, label %label44, label %label45
label40: ; preds = %label30
%op41 = icmp slt i32 %op31, 0
%op42 = zext i1 %op41 to i32
%op43 = icmp ne i32 %op42, 0
br i1 %op43, label %label51, label %label53
label44: ; preds = %label37
call void @neg_idx_except()
ret i32 0
label45: ; preds = %label37
%op46 = getelementptr [20000000 x i32], [20000000 x i32]* @matrix, i32 0, i32 %op32
%op47 = load i32, i32* %op46
%op48 = mul i32 %op38, %op47
%op49 = add i32 %op31, %op48
%op50 = add i32 %op32, 1
br label %label30
label51: ; preds = %label40
%op52 = sub i32 0, %op31
br label %label53
label53: ; preds = %label40, %label51
%op54 = phi i32 [ %op31, %label40 ], [ %op52, %label51 ]
call void @output(i32 %op54)
ret i32 0
}
void main(void) {
int c;
int a;
int b;
int d;
int f;
int g;
int loopCnt;
loopCnt = input();
c = 0;
a = 0;
g = 0;
while (c < loopCnt) {
a = 1.23456 * 5.73478 * 2.3333 * 4.3673 * 6.34636;
b = a * a * a * a * a * a;
d = b * b * b * b * b * b;
f = d * d * d * d * d * d;
g = f * f * f * f * f * f;
c = c + 1;
}
output(g);
return;
}
\ No newline at end of file
int matrix[20000000];
int ad[100000];
int len;
void readarray(void) {
int cnt;
cnt = 0;
while (cnt < len) {
ad[cnt] = input();
cnt = cnt + 1;
}
}
int transpose(int n, int matrix[], int rowsize) {
int colsize;
int i;
int j;
int curr;
colsize = n / rowsize;
i = 0;
j = 0;
while (i < colsize) {
j = 0;
while (j < rowsize) {
if (i < j) {
j = j + 1;
} else {
curr = matrix[i * rowsize + j];
matrix[j * colsize + i] = matrix[i * rowsize + j];
matrix[i * rowsize + j] = curr;
j = j + 1;
}
}
i = i + 1;
}
return 0 - 1;
}
int main(void) {
int n;
int i;
int ans;
n = input();
len = input();
readarray();
i = 0;
while (i < n) {
matrix[i] = i;
i = i + 1;
}
i = 0;
while (i < len) {
transpose(n, matrix, ad[i]);
i = i + 1;
}
ans = 0;
i = 0;
while (i < len) {
ans = ans + i * i * matrix[i];
i = i + 1;
}
if (ans < 0) {
ans = 0 - ans;
}
output(ans);
return 0;
}
10000000
30
2
5
4
25
8
125
16
625
32
3125
2
5
4
25
8
125
16
625
32
3125
2
5
4
25
8
125
16
625
32
3125
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment