1 //==-- loop_proto_to_cxx.cpp - Protobuf-C++ conversion ---------------------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implements functions for converting between protobufs and C++. Differs from
10 // proto_to_cxx.cpp by wrapping all the generated C++ code in either a single
11 // for loop or two nested loops. Also outputs a different function signature
12 // that includes a size_t parameter for the loop to use. The C++ code generated
13 // is meant to stress the LLVM loop vectorizer.
14 //
15 // Still a work in progress.
16 //
17 //===----------------------------------------------------------------------===//
18 
19 #include "cxx_loop_proto.pb.h"
20 #include "proto_to_cxx.h"
21 
22 // The following is needed to convert protos in human-readable form
23 #include <google/protobuf/text_format.h>
24 
25 #include <ostream>
26 #include <sstream>
27 
28 namespace clang_fuzzer {
29 
30 static bool inner_loop = false;
31 class InnerLoop {
32   public:
InnerLoop()33   InnerLoop() {
34     inner_loop = true;
35   }
~InnerLoop()36   ~InnerLoop() {
37     inner_loop = false;
38   }
39 };
40 
41 // Forward decls.
42 std::ostream &operator<<(std::ostream &os, const BinaryOp &x);
43 std::ostream &operator<<(std::ostream &os, const StatementSeq &x);
44 
45 // Proto to C++.
operator <<(std::ostream & os,const Const & x)46 std::ostream &operator<<(std::ostream &os, const Const &x) {
47   return os << "(" << x.val() << ")";
48 }
operator <<(std::ostream & os,const VarRef & x)49 std::ostream &operator<<(std::ostream &os, const VarRef &x) {
50   std::string which_loop = inner_loop ? "j" : "i";
51   switch (x.arr()) {
52     case VarRef::ARR_A:
53       return os << "a[" << which_loop << "]";
54     case VarRef::ARR_B:
55       return os << "b[" << which_loop << "]";
56     case VarRef::ARR_C:
57       return os << "c[" << which_loop << "]";
58   }
59 }
operator <<(std::ostream & os,const Rvalue & x)60 std::ostream &operator<<(std::ostream &os, const Rvalue &x) {
61   if (x.has_cons())
62     return os << x.cons();
63   if (x.has_binop())
64     return os << x.binop();
65   if (x.has_varref())
66     return os << x.varref();
67   return os << "1";
68 }
operator <<(std::ostream & os,const BinaryOp & x)69 std::ostream &operator<<(std::ostream &os, const BinaryOp &x) {
70   os << "(" << x.left();
71   switch (x.op()) {
72   case BinaryOp::PLUS:
73     os << "+";
74     break;
75   case BinaryOp::MINUS:
76     os << "-";
77     break;
78   case BinaryOp::MUL:
79     os << "*";
80     break;
81   case BinaryOp::XOR:
82     os << "^";
83     break;
84   case BinaryOp::AND:
85     os << "&";
86     break;
87   case BinaryOp::OR:
88     os << "|";
89     break;
90   case BinaryOp::EQ:
91     os << "==";
92     break;
93   case BinaryOp::NE:
94     os << "!=";
95     break;
96   case BinaryOp::LE:
97     os << "<=";
98     break;
99   case BinaryOp::GE:
100     os << ">=";
101     break;
102   case BinaryOp::LT:
103     os << "<";
104     break;
105   case BinaryOp::GT:
106     os << ">";
107     break;
108   }
109   return os << x.right() << ")";
110 }
operator <<(std::ostream & os,const AssignmentStatement & x)111 std::ostream &operator<<(std::ostream &os, const AssignmentStatement &x) {
112   return os << x.varref() << "=" << x.rvalue() << ";\n";
113 }
operator <<(std::ostream & os,const Statement & x)114 std::ostream &operator<<(std::ostream &os, const Statement &x) {
115   return os << x.assignment();
116 }
operator <<(std::ostream & os,const StatementSeq & x)117 std::ostream &operator<<(std::ostream &os, const StatementSeq &x) {
118   for (auto &st : x.statements())
119     os << st;
120   return os;
121 }
NestedLoopToString(std::ostream & os,const LoopFunction & x)122 void NestedLoopToString(std::ostream &os, const LoopFunction &x) {
123   os << "void foo(int *a, int *b, int *__restrict__ c, size_t s) {\n"
124      << "for (int i=0; i<s; i++){\n"
125      << "for (int j=0; j<s; j++){\n";
126   {
127     InnerLoop IL;
128     os << x.inner_statements() << "}\n";
129   }
130   os << x.outer_statements() << "}\n}\n";
131 }
SingleLoopToString(std::ostream & os,const LoopFunction & x)132 void SingleLoopToString(std::ostream &os, const LoopFunction &x) {
133   os << "void foo(int *a, int *b, int *__restrict__ c, size_t s) {\n"
134      << "for (int i=0; i<s; i++){\n"
135      << x.outer_statements() << "}\n}\n";
136 }
operator <<(std::ostream & os,const LoopFunction & x)137 std::ostream &operator<<(std::ostream &os, const LoopFunction &x) {
138   if (x.has_inner_statements())
139     NestedLoopToString(os, x);
140   else
141     SingleLoopToString(os, x);
142   return os;
143 }
144 
145 // ---------------------------------
146 
LoopFunctionToString(const LoopFunction & input)147 std::string LoopFunctionToString(const LoopFunction &input) {
148   std::ostringstream os;
149   os << input;
150   return os.str();
151 }
LoopProtoToCxx(const uint8_t * data,size_t size)152 std::string LoopProtoToCxx(const uint8_t *data, size_t size) {
153   LoopFunction message;
154   if (!message.ParsePartialFromArray(data, size))
155     return "#error invalid proto\n";
156   return LoopFunctionToString(message);
157 }
158 
159 } // namespace clang_fuzzer
160