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