blob: 114f5fc40ed786e4b8f2b33843089f6f74578a44 [file] [log] [blame]
//==-- loop_proto_to_cxx.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 C++. Differs from
// proto_to_cxx.cpp by wrapping all the generated C++ code in either a single
// for loop or two nested loops. Also outputs a different function signature
// that includes a size_t parameter for the loop to use. The C++ code generated
// is meant to stress the LLVM loop vectorizer.
//
// Still a work in progress.
//
//===----------------------------------------------------------------------===//
#include "cxx_loop_proto.pb.h"
#include "proto_to_cxx.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 {
static bool inner_loop = false;
class InnerLoop {
public:
InnerLoop() {
inner_loop = true;
}
~InnerLoop() {
inner_loop = false;
}
};
// Forward decls.
std::ostream &operator<<(std::ostream &os, const BinaryOp &x);
std::ostream &operator<<(std::ostream &os, const StatementSeq &x);
// Proto to C++.
std::ostream &operator<<(std::ostream &os, const Const &x) {
return os << "(" << x.val() << ")";
}
std::ostream &operator<<(std::ostream &os, const VarRef &x) {
std::string which_loop = inner_loop ? "j" : "i";
switch (x.arr()) {
case VarRef::ARR_A:
return os << "a[" << which_loop << "]";
case VarRef::ARR_B:
return os << "b[" << which_loop << "]";
case VarRef::ARR_C:
return os << "c[" << which_loop << "]";
}
}
std::ostream &operator<<(std::ostream &os, const Rvalue &x) {
if (x.has_cons())
return os << x.cons();
if (x.has_binop())
return os << x.binop();
if (x.has_varref())
return os << x.varref();
return os << "1";
}
std::ostream &operator<<(std::ostream &os, const BinaryOp &x) {
os << "(" << x.left();
switch (x.op()) {
case BinaryOp::PLUS:
os << "+";
break;
case BinaryOp::MINUS:
os << "-";
break;
case BinaryOp::MUL:
os << "*";
break;
case BinaryOp::XOR:
os << "^";
break;
case BinaryOp::AND:
os << "&";
break;
case BinaryOp::OR:
os << "|";
break;
case BinaryOp::EQ:
os << "==";
break;
case BinaryOp::NE:
os << "!=";
break;
case BinaryOp::LE:
os << "<=";
break;
case BinaryOp::GE:
os << ">=";
break;
case BinaryOp::LT:
os << "<";
break;
case BinaryOp::GT:
os << ">";
break;
}
return os << x.right() << ")";
}
std::ostream &operator<<(std::ostream &os, const AssignmentStatement &x) {
return os << x.varref() << "=" << x.rvalue() << ";\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 << "void foo(int *a, int *b, int *__restrict__ c, size_t s) {\n"
<< "for (int i=0; i<s; i++){\n"
<< "for (int j=0; j<s; j++){\n";
{
InnerLoop IL;
os << x.inner_statements() << "}\n";
}
os << x.outer_statements() << "}\n}\n";
}
void SingleLoopToString(std::ostream &os, const LoopFunction &x) {
os << "void foo(int *a, int *b, int *__restrict__ c, size_t s) {\n"
<< "for (int i=0; i<s; i++){\n"
<< x.outer_statements() << "}\n}\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 LoopFunctionToString(const LoopFunction &input) {
std::ostringstream os;
os << input;
return os.str();
}
std::string LoopProtoToCxx(const uint8_t *data, size_t size) {
LoopFunction message;
if (!message.ParsePartialFromArray(data, size))
return "#error invalid proto\n";
return LoopFunctionToString(message);
}
} // namespace clang_fuzzer