1e5f4a9ffSEmmett Neyman //==-- loop_proto_to_llvm.cpp - Protobuf-C++ conversion
2e5f4a9ffSEmmett Neyman //---------------------==//
3e5f4a9ffSEmmett Neyman //
4*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
6*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7e5f4a9ffSEmmett Neyman //
8e5f4a9ffSEmmett Neyman //===----------------------------------------------------------------------===//
9e5f4a9ffSEmmett Neyman //
10e5f4a9ffSEmmett Neyman // Implements functions for converting between protobufs and LLVM IR.
11e5f4a9ffSEmmett Neyman //
12e5f4a9ffSEmmett Neyman //
13e5f4a9ffSEmmett Neyman //===----------------------------------------------------------------------===//
14e5f4a9ffSEmmett Neyman
15e5f4a9ffSEmmett Neyman #include "loop_proto_to_llvm.h"
16e5f4a9ffSEmmett Neyman #include "cxx_loop_proto.pb.h"
177da7b568SEmmett Neyman #include "../handle-llvm/input_arrays.h"
18e5f4a9ffSEmmett Neyman
19e5f4a9ffSEmmett Neyman // The following is needed to convert protos in human-readable form
20e5f4a9ffSEmmett Neyman #include <google/protobuf/text_format.h>
21e5f4a9ffSEmmett Neyman
22e5f4a9ffSEmmett Neyman #include <ostream>
23e5f4a9ffSEmmett Neyman #include <sstream>
24e5f4a9ffSEmmett Neyman
25e5f4a9ffSEmmett Neyman namespace clang_fuzzer {
26e5f4a9ffSEmmett Neyman
27e5f4a9ffSEmmett Neyman // Forward decls
28e5f4a9ffSEmmett Neyman std::string BinopToString(std::ostream &os, const BinaryOp &x);
29e5f4a9ffSEmmett Neyman std::string StateSeqToString(std::ostream &os, const StatementSeq &x);
30e5f4a9ffSEmmett Neyman
31e5f4a9ffSEmmett Neyman // Counter variable to generate new LLVM IR variable names and wrapper function
get_var()32ba58c3a3SEmmett Neyman static std::string get_var() {
33e5f4a9ffSEmmett Neyman static int ctr = 0;
34e5f4a9ffSEmmett Neyman return "%var" + std::to_string(ctr++);
35e5f4a9ffSEmmett Neyman }
36e5f4a9ffSEmmett Neyman
37ba58c3a3SEmmett Neyman static bool inner_loop = false;
38ba58c3a3SEmmett Neyman class InnerLoop {
39ba58c3a3SEmmett Neyman public:
InnerLoop()40ba58c3a3SEmmett Neyman InnerLoop() {
41ba58c3a3SEmmett Neyman inner_loop = true;
42ba58c3a3SEmmett Neyman }
~InnerLoop()43ba58c3a3SEmmett Neyman ~InnerLoop() {
44ba58c3a3SEmmett Neyman inner_loop = false;
45ba58c3a3SEmmett Neyman }
46ba58c3a3SEmmett Neyman };
47ba58c3a3SEmmett Neyman
48ba58c3a3SEmmett Neyman
49e5f4a9ffSEmmett Neyman // Proto to LLVM.
50e5f4a9ffSEmmett Neyman
ConstToString(const Const & x)51e5f4a9ffSEmmett Neyman std::string ConstToString(const Const &x) {
52e5f4a9ffSEmmett Neyman return std::to_string(x.val());
53e5f4a9ffSEmmett Neyman }
VarRefToString(std::ostream & os,const VarRef & x)54e5f4a9ffSEmmett Neyman std::string VarRefToString(std::ostream &os, const VarRef &x) {
55ba58c3a3SEmmett Neyman std::string which_loop = inner_loop ? "inner" : "outer";
56e5f4a9ffSEmmett Neyman std::string arr;
57e5f4a9ffSEmmett Neyman switch(x.arr()) {
58e5f4a9ffSEmmett Neyman case VarRef::ARR_A:
59e5f4a9ffSEmmett Neyman arr = "%a";
60e5f4a9ffSEmmett Neyman break;
61e5f4a9ffSEmmett Neyman case VarRef::ARR_B:
62e5f4a9ffSEmmett Neyman arr = "%b";
63e5f4a9ffSEmmett Neyman break;
64e5f4a9ffSEmmett Neyman case VarRef::ARR_C:
65e5f4a9ffSEmmett Neyman arr = "%c";
66e5f4a9ffSEmmett Neyman break;
67e5f4a9ffSEmmett Neyman }
68e5f4a9ffSEmmett Neyman std::string ptr_var = get_var();
69ba58c3a3SEmmett Neyman os << ptr_var << " = getelementptr inbounds i32, i32* " << arr
70ba58c3a3SEmmett Neyman << ", i64 %" << which_loop << "_ct\n";
71e5f4a9ffSEmmett Neyman return ptr_var;
72e5f4a9ffSEmmett Neyman }
RvalueToString(std::ostream & os,const Rvalue & x)73e5f4a9ffSEmmett Neyman std::string RvalueToString(std::ostream &os, const Rvalue &x) {
74e5f4a9ffSEmmett Neyman if(x.has_cons())
75e5f4a9ffSEmmett Neyman return ConstToString(x.cons());
76e5f4a9ffSEmmett Neyman if(x.has_binop())
77e5f4a9ffSEmmett Neyman return BinopToString(os, x.binop());
78e5f4a9ffSEmmett Neyman if(x.has_varref()) {
79e5f4a9ffSEmmett Neyman std::string var_ref = VarRefToString(os, x.varref());
80e5f4a9ffSEmmett Neyman std::string val_var = get_var();
81e5f4a9ffSEmmett Neyman os << val_var << " = load i32, i32* " << var_ref << "\n";
82e5f4a9ffSEmmett Neyman return val_var;
83e5f4a9ffSEmmett Neyman }
84e5f4a9ffSEmmett Neyman return "1";
85e5f4a9ffSEmmett Neyman
86e5f4a9ffSEmmett Neyman }
BinopToString(std::ostream & os,const BinaryOp & x)87e5f4a9ffSEmmett Neyman std::string BinopToString(std::ostream &os, const BinaryOp &x) {
88e5f4a9ffSEmmett Neyman std::string left = RvalueToString(os, x.left());
89e5f4a9ffSEmmett Neyman std::string right = RvalueToString(os, x.right());
90e5f4a9ffSEmmett Neyman std::string op;
91e5f4a9ffSEmmett Neyman switch (x.op()) {
92e5f4a9ffSEmmett Neyman case BinaryOp::PLUS:
93e5f4a9ffSEmmett Neyman op = "add";
94e5f4a9ffSEmmett Neyman break;
95e5f4a9ffSEmmett Neyman case BinaryOp::MINUS:
96e5f4a9ffSEmmett Neyman op = "sub";
97e5f4a9ffSEmmett Neyman break;
98e5f4a9ffSEmmett Neyman case BinaryOp::MUL:
99e5f4a9ffSEmmett Neyman op = "mul";
100e5f4a9ffSEmmett Neyman break;
101e5f4a9ffSEmmett Neyman case BinaryOp::XOR:
102e5f4a9ffSEmmett Neyman op = "xor";
103e5f4a9ffSEmmett Neyman break;
104e5f4a9ffSEmmett Neyman case BinaryOp::AND:
105e5f4a9ffSEmmett Neyman op = "and";
106e5f4a9ffSEmmett Neyman break;
107e5f4a9ffSEmmett Neyman case BinaryOp::OR:
108e5f4a9ffSEmmett Neyman op = "or";
109e5f4a9ffSEmmett Neyman break;
110e5f4a9ffSEmmett Neyman // Support for Boolean operators will be added later
111e5f4a9ffSEmmett Neyman case BinaryOp::EQ:
112e5f4a9ffSEmmett Neyman case BinaryOp::NE:
113e5f4a9ffSEmmett Neyman case BinaryOp::LE:
114e5f4a9ffSEmmett Neyman case BinaryOp::GE:
115e5f4a9ffSEmmett Neyman case BinaryOp::LT:
116e5f4a9ffSEmmett Neyman case BinaryOp::GT:
117e5f4a9ffSEmmett Neyman op = "add";
118e5f4a9ffSEmmett Neyman break;
119e5f4a9ffSEmmett Neyman }
120e5f4a9ffSEmmett Neyman std::string val_var = get_var();
121e5f4a9ffSEmmett Neyman os << val_var << " = " << op << " i32 " << left << ", " << right << "\n";
122e5f4a9ffSEmmett Neyman return val_var;
123e5f4a9ffSEmmett Neyman }
operator <<(std::ostream & os,const AssignmentStatement & x)124e5f4a9ffSEmmett Neyman std::ostream &operator<<(std::ostream &os, const AssignmentStatement &x) {
125e5f4a9ffSEmmett Neyman std::string rvalue = RvalueToString(os, x.rvalue());
126e5f4a9ffSEmmett Neyman std::string var_ref = VarRefToString(os, x.varref());
127e5f4a9ffSEmmett Neyman return os << "store i32 " << rvalue << ", i32* " << var_ref << "\n";
128e5f4a9ffSEmmett Neyman }
operator <<(std::ostream & os,const Statement & x)129e5f4a9ffSEmmett Neyman std::ostream &operator<<(std::ostream &os, const Statement &x) {
130e5f4a9ffSEmmett Neyman return os << x.assignment();
131e5f4a9ffSEmmett Neyman }
operator <<(std::ostream & os,const StatementSeq & x)132e5f4a9ffSEmmett Neyman std::ostream &operator<<(std::ostream &os, const StatementSeq &x) {
133e5f4a9ffSEmmett Neyman for (auto &st : x.statements()) {
134e5f4a9ffSEmmett Neyman os << st;
135e5f4a9ffSEmmett Neyman }
136e5f4a9ffSEmmett Neyman return os;
137e5f4a9ffSEmmett Neyman }
NestedLoopToString(std::ostream & os,const LoopFunction & x)138ba58c3a3SEmmett Neyman void NestedLoopToString(std::ostream &os, const LoopFunction &x) {
139ba58c3a3SEmmett Neyman os << "target triple = \"x86_64-unknown-linux-gnu\"\n"
140ba58c3a3SEmmett Neyman << "define void @foo(i32* %a, i32* %b, i32* noalias %c, i64 %s) {\n"
141ba58c3a3SEmmett Neyman << "outer_loop_start:\n"
142ba58c3a3SEmmett Neyman << "%cmp = icmp sgt i64 %s, 0\n"
143ba58c3a3SEmmett Neyman << "br i1 %cmp, label %inner_loop_start, label %end\n"
144ba58c3a3SEmmett Neyman << "outer_loop:\n"
145ba58c3a3SEmmett Neyman << x.outer_statements()
146ba58c3a3SEmmett Neyman << "%o_ct_new = add i64 %outer_ct, 1\n"
147ba58c3a3SEmmett Neyman << "%jmp_outer = icmp eq i64 %o_ct_new, %s\n"
148ba58c3a3SEmmett Neyman << "br i1 %jmp_outer, label %end, label %inner_loop_start\n"
149ba58c3a3SEmmett Neyman << "inner_loop_start:\n"
150ba58c3a3SEmmett Neyman << "%outer_ct = phi i64 [%o_ct_new, %outer_loop], [0, %outer_loop_start]\n"
151ba58c3a3SEmmett Neyman << "br label %inner_loop\n"
152ba58c3a3SEmmett Neyman << "inner_loop:\n"
153ba58c3a3SEmmett Neyman << "%inner_ct = phi i64 [0, %inner_loop_start], [%i_ct_new, %inner_loop]\n";
154ba58c3a3SEmmett Neyman {
155ba58c3a3SEmmett Neyman InnerLoop IL;
156ba58c3a3SEmmett Neyman os << x.inner_statements();
157ba58c3a3SEmmett Neyman }
158ba58c3a3SEmmett Neyman os << "%i_ct_new = add i64 %inner_ct, 1\n"
159ba58c3a3SEmmett Neyman << "%jmp_inner = icmp eq i64 %i_ct_new, %s\n"
160ba58c3a3SEmmett Neyman << "br i1 %jmp_inner, label %outer_loop, label %inner_loop, !llvm.loop !0\n"
161ba58c3a3SEmmett Neyman << "end:\n"
162ba58c3a3SEmmett Neyman << "ret void\n"
163ba58c3a3SEmmett Neyman << "}\n"
164ba58c3a3SEmmett Neyman << "!0 = distinct !{!0, !1, !2}\n"
165ba58c3a3SEmmett Neyman << "!1 = !{!\"llvm.loop.vectorize.enable\", i1 true}\n"
166ba58c3a3SEmmett Neyman << "!2 = !{!\"llvm.loop.vectorize.width\", i32 " << kArraySize << "}\n";
167ba58c3a3SEmmett Neyman }
SingleLoopToString(std::ostream & os,const LoopFunction & x)168ba58c3a3SEmmett Neyman void SingleLoopToString(std::ostream &os, const LoopFunction &x) {
169ba58c3a3SEmmett Neyman os << "target triple = \"x86_64-unknown-linux-gnu\"\n"
170ba58c3a3SEmmett Neyman << "define void @foo(i32* %a, i32* %b, i32* noalias %c, i64 %s) {\n"
171ba58c3a3SEmmett Neyman << "%cmp = icmp sgt i64 %s, 0\n"
172ba58c3a3SEmmett Neyman << "br i1 %cmp, label %start, label %end\n"
173673269edSEmmett Neyman << "start:\n"
174673269edSEmmett Neyman << "br label %loop\n"
175673269edSEmmett Neyman << "end:\n"
176673269edSEmmett Neyman << "ret void\n"
177e5f4a9ffSEmmett Neyman << "loop:\n"
178ba58c3a3SEmmett Neyman << "%outer_ct = phi i64 [ %ctnew, %loop ], [ 0, %start ]\n"
179ba58c3a3SEmmett Neyman << x.outer_statements()
180ba58c3a3SEmmett Neyman << "%ctnew = add i64 %outer_ct, 1\n"
181673269edSEmmett Neyman << "%j = icmp eq i64 %ctnew, %s\n"
1827da7b568SEmmett Neyman << "br i1 %j, label %end, label %loop, !llvm.loop !0\n}\n"
1837da7b568SEmmett Neyman << "!0 = distinct !{!0, !1, !2}\n"
1847da7b568SEmmett Neyman << "!1 = !{!\"llvm.loop.vectorize.enable\", i1 true}\n"
185ba58c3a3SEmmett Neyman << "!2 = !{!\"llvm.loop.vectorize.width\", i32 " << kArraySize << "}\n";
186ba58c3a3SEmmett Neyman }
operator <<(std::ostream & os,const LoopFunction & x)187ba58c3a3SEmmett Neyman std::ostream &operator<<(std::ostream &os, const LoopFunction &x) {
188ba58c3a3SEmmett Neyman if (x.has_inner_statements())
189ba58c3a3SEmmett Neyman NestedLoopToString(os, x);
190ba58c3a3SEmmett Neyman else
191ba58c3a3SEmmett Neyman SingleLoopToString(os, x);
192ba58c3a3SEmmett Neyman return os;
193e5f4a9ffSEmmett Neyman }
194e5f4a9ffSEmmett Neyman
195e5f4a9ffSEmmett Neyman // ---------------------------------
196e5f4a9ffSEmmett Neyman
LoopFunctionToLLVMString(const LoopFunction & input)197e5f4a9ffSEmmett Neyman std::string LoopFunctionToLLVMString(const LoopFunction &input) {
198e5f4a9ffSEmmett Neyman std::ostringstream os;
199e5f4a9ffSEmmett Neyman os << input;
200e5f4a9ffSEmmett Neyman return os.str();
201e5f4a9ffSEmmett Neyman }
LoopProtoToLLVM(const uint8_t * data,size_t size)202e5f4a9ffSEmmett Neyman std::string LoopProtoToLLVM(const uint8_t *data, size_t size) {
203e5f4a9ffSEmmett Neyman LoopFunction message;
204e5f4a9ffSEmmett Neyman if (!message.ParsePartialFromArray(data, size))
205e5f4a9ffSEmmett Neyman return "#error invalid proto\n";
206e5f4a9ffSEmmett Neyman return LoopFunctionToLLVMString(message);
207e5f4a9ffSEmmett Neyman }
208e5f4a9ffSEmmett Neyman
209e5f4a9ffSEmmett Neyman } // namespace clang_fuzzer
210