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: |
33 | InnerLoop() { |
34 | inner_loop = true; |
35 | } |
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++. |
46 | std::ostream &operator<<(std::ostream &os, const Const &x) { |
47 | return os << "(" << x.val() << ")" ; |
48 | } |
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 | } |
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 | } |
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 | } |
111 | std::ostream &operator<<(std::ostream &os, const AssignmentStatement &x) { |
112 | return os << x.varref() << "=" << x.rvalue() << ";\n" ; |
113 | } |
114 | std::ostream &operator<<(std::ostream &os, const Statement &x) { |
115 | return os << x.assignment(); |
116 | } |
117 | std::ostream &operator<<(std::ostream &os, const StatementSeq &x) { |
118 | for (auto &st : x.statements()) |
119 | os << st; |
120 | return os; |
121 | } |
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 | } |
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 | } |
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 | |
147 | std::string LoopFunctionToString(const LoopFunction &input) { |
148 | std::ostringstream os; |
149 | os << input; |
150 | return os.str(); |
151 | } |
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 | |