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