mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-19 19:45:40 -04:00

to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
210 lines
6.1 KiB
C++
210 lines
6.1 KiB
C++
//==-- loop_proto_to_llvm.cpp - Protobuf-C++ conversion
|
|
//---------------------==//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Implements functions for converting between protobufs and LLVM IR.
|
|
//
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "loop_proto_to_llvm.h"
|
|
#include "cxx_loop_proto.pb.h"
|
|
#include "../handle-llvm/input_arrays.h"
|
|
|
|
// The following is needed to convert protos in human-readable form
|
|
#include <google/protobuf/text_format.h>
|
|
|
|
#include <ostream>
|
|
#include <sstream>
|
|
|
|
namespace clang_fuzzer {
|
|
|
|
// Forward decls
|
|
std::string BinopToString(std::ostream &os, const BinaryOp &x);
|
|
std::string StateSeqToString(std::ostream &os, const StatementSeq &x);
|
|
|
|
// Counter variable to generate new LLVM IR variable names and wrapper function
|
|
static std::string get_var() {
|
|
static int ctr = 0;
|
|
return "%var" + std::to_string(ctr++);
|
|
}
|
|
|
|
static bool inner_loop = false;
|
|
class InnerLoop {
|
|
public:
|
|
InnerLoop() {
|
|
inner_loop = true;
|
|
}
|
|
~InnerLoop() {
|
|
inner_loop = false;
|
|
}
|
|
};
|
|
|
|
|
|
// Proto to LLVM.
|
|
|
|
std::string ConstToString(const Const &x) {
|
|
return std::to_string(x.val());
|
|
}
|
|
std::string VarRefToString(std::ostream &os, const VarRef &x) {
|
|
std::string which_loop = inner_loop ? "inner" : "outer";
|
|
std::string arr;
|
|
switch(x.arr()) {
|
|
case VarRef::ARR_A:
|
|
arr = "%a";
|
|
break;
|
|
case VarRef::ARR_B:
|
|
arr = "%b";
|
|
break;
|
|
case VarRef::ARR_C:
|
|
arr = "%c";
|
|
break;
|
|
}
|
|
std::string ptr_var = get_var();
|
|
os << ptr_var << " = getelementptr inbounds i32, i32* " << arr
|
|
<< ", i64 %" << which_loop << "_ct\n";
|
|
return ptr_var;
|
|
}
|
|
std::string RvalueToString(std::ostream &os, const Rvalue &x) {
|
|
if(x.has_cons())
|
|
return ConstToString(x.cons());
|
|
if(x.has_binop())
|
|
return BinopToString(os, x.binop());
|
|
if(x.has_varref()) {
|
|
std::string var_ref = VarRefToString(os, x.varref());
|
|
std::string val_var = get_var();
|
|
os << val_var << " = load i32, i32* " << var_ref << "\n";
|
|
return val_var;
|
|
}
|
|
return "1";
|
|
|
|
}
|
|
std::string BinopToString(std::ostream &os, const BinaryOp &x) {
|
|
std::string left = RvalueToString(os, x.left());
|
|
std::string right = RvalueToString(os, x.right());
|
|
std::string op;
|
|
switch (x.op()) {
|
|
case BinaryOp::PLUS:
|
|
op = "add";
|
|
break;
|
|
case BinaryOp::MINUS:
|
|
op = "sub";
|
|
break;
|
|
case BinaryOp::MUL:
|
|
op = "mul";
|
|
break;
|
|
case BinaryOp::XOR:
|
|
op = "xor";
|
|
break;
|
|
case BinaryOp::AND:
|
|
op = "and";
|
|
break;
|
|
case BinaryOp::OR:
|
|
op = "or";
|
|
break;
|
|
// Support for Boolean operators will be added later
|
|
case BinaryOp::EQ:
|
|
case BinaryOp::NE:
|
|
case BinaryOp::LE:
|
|
case BinaryOp::GE:
|
|
case BinaryOp::LT:
|
|
case BinaryOp::GT:
|
|
op = "add";
|
|
break;
|
|
}
|
|
std::string val_var = get_var();
|
|
os << val_var << " = " << op << " i32 " << left << ", " << right << "\n";
|
|
return val_var;
|
|
}
|
|
std::ostream &operator<<(std::ostream &os, const AssignmentStatement &x) {
|
|
std::string rvalue = RvalueToString(os, x.rvalue());
|
|
std::string var_ref = VarRefToString(os, x.varref());
|
|
return os << "store i32 " << rvalue << ", i32* " << var_ref << "\n";
|
|
}
|
|
std::ostream &operator<<(std::ostream &os, const Statement &x) {
|
|
return os << x.assignment();
|
|
}
|
|
std::ostream &operator<<(std::ostream &os, const StatementSeq &x) {
|
|
for (auto &st : x.statements()) {
|
|
os << st;
|
|
}
|
|
return os;
|
|
}
|
|
void NestedLoopToString(std::ostream &os, const LoopFunction &x) {
|
|
os << "target triple = \"x86_64-unknown-linux-gnu\"\n"
|
|
<< "define void @foo(i32* %a, i32* %b, i32* noalias %c, i64 %s) {\n"
|
|
<< "outer_loop_start:\n"
|
|
<< "%cmp = icmp sgt i64 %s, 0\n"
|
|
<< "br i1 %cmp, label %inner_loop_start, label %end\n"
|
|
<< "outer_loop:\n"
|
|
<< x.outer_statements()
|
|
<< "%o_ct_new = add i64 %outer_ct, 1\n"
|
|
<< "%jmp_outer = icmp eq i64 %o_ct_new, %s\n"
|
|
<< "br i1 %jmp_outer, label %end, label %inner_loop_start\n"
|
|
<< "inner_loop_start:\n"
|
|
<< "%outer_ct = phi i64 [%o_ct_new, %outer_loop], [0, %outer_loop_start]\n"
|
|
<< "br label %inner_loop\n"
|
|
<< "inner_loop:\n"
|
|
<< "%inner_ct = phi i64 [0, %inner_loop_start], [%i_ct_new, %inner_loop]\n";
|
|
{
|
|
InnerLoop IL;
|
|
os << x.inner_statements();
|
|
}
|
|
os << "%i_ct_new = add i64 %inner_ct, 1\n"
|
|
<< "%jmp_inner = icmp eq i64 %i_ct_new, %s\n"
|
|
<< "br i1 %jmp_inner, label %outer_loop, label %inner_loop, !llvm.loop !0\n"
|
|
<< "end:\n"
|
|
<< "ret void\n"
|
|
<< "}\n"
|
|
<< "!0 = distinct !{!0, !1, !2}\n"
|
|
<< "!1 = !{!\"llvm.loop.vectorize.enable\", i1 true}\n"
|
|
<< "!2 = !{!\"llvm.loop.vectorize.width\", i32 " << kArraySize << "}\n";
|
|
}
|
|
void SingleLoopToString(std::ostream &os, const LoopFunction &x) {
|
|
os << "target triple = \"x86_64-unknown-linux-gnu\"\n"
|
|
<< "define void @foo(i32* %a, i32* %b, i32* noalias %c, i64 %s) {\n"
|
|
<< "%cmp = icmp sgt i64 %s, 0\n"
|
|
<< "br i1 %cmp, label %start, label %end\n"
|
|
<< "start:\n"
|
|
<< "br label %loop\n"
|
|
<< "end:\n"
|
|
<< "ret void\n"
|
|
<< "loop:\n"
|
|
<< "%outer_ct = phi i64 [ %ctnew, %loop ], [ 0, %start ]\n"
|
|
<< x.outer_statements()
|
|
<< "%ctnew = add i64 %outer_ct, 1\n"
|
|
<< "%j = icmp eq i64 %ctnew, %s\n"
|
|
<< "br i1 %j, label %end, label %loop, !llvm.loop !0\n}\n"
|
|
<< "!0 = distinct !{!0, !1, !2}\n"
|
|
<< "!1 = !{!\"llvm.loop.vectorize.enable\", i1 true}\n"
|
|
<< "!2 = !{!\"llvm.loop.vectorize.width\", i32 " << kArraySize << "}\n";
|
|
}
|
|
std::ostream &operator<<(std::ostream &os, const LoopFunction &x) {
|
|
if (x.has_inner_statements())
|
|
NestedLoopToString(os, x);
|
|
else
|
|
SingleLoopToString(os, x);
|
|
return os;
|
|
}
|
|
|
|
// ---------------------------------
|
|
|
|
std::string LoopFunctionToLLVMString(const LoopFunction &input) {
|
|
std::ostringstream os;
|
|
os << input;
|
|
return os.str();
|
|
}
|
|
std::string LoopProtoToLLVM(const uint8_t *data, size_t size) {
|
|
LoopFunction message;
|
|
if (!message.ParsePartialFromArray(data, size))
|
|
return "#error invalid proto\n";
|
|
return LoopFunctionToLLVMString(message);
|
|
}
|
|
|
|
} // namespace clang_fuzzer
|