Clang Project

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