1 //==-- loop_proto_to_llvm.cpp - Protobuf-C++ conversion
2 //---------------------==//
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
8 //===----------------------------------------------------------------------===//
10 // Implements functions for converting between protobufs and LLVM IR.
13 //===----------------------------------------------------------------------===//
15 #include "loop_proto_to_llvm.h"
16 #include "cxx_loop_proto.pb.h"
17 #include "../handle-llvm/input_arrays.h"
19 // The following is needed to convert protos in human-readable form
20 #include <google/protobuf/text_format.h>
25 namespace clang_fuzzer
{
28 std::string
BinopToString(std::ostream
&os
, const BinaryOp
&x
);
29 std::string
StateSeqToString(std::ostream
&os
, const StatementSeq
&x
);
31 // Counter variable to generate new LLVM IR variable names and wrapper function
32 static std::string
get_var() {
34 return "%var" + std::to_string(ctr
++);
37 static bool inner_loop
= false;
51 std::string
ConstToString(const Const
&x
) {
52 return std::to_string(x
.val());
54 std::string
VarRefToString(std::ostream
&os
, const VarRef
&x
) {
55 std::string which_loop
= inner_loop
? "inner" : "outer";
68 std::string ptr_var
= get_var();
69 os
<< ptr_var
<< " = getelementptr inbounds i32, i32* " << arr
70 << ", i64 %" << which_loop
<< "_ct\n";
73 std::string
RvalueToString(std::ostream
&os
, const Rvalue
&x
) {
75 return ConstToString(x
.cons());
77 return BinopToString(os
, x
.binop());
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";
87 std::string
BinopToString(std::ostream
&os
, const BinaryOp
&x
) {
88 std::string left
= RvalueToString(os
, x
.left());
89 std::string right
= RvalueToString(os
, x
.right());
110 // Support for Boolean operators will be added later
120 std::string val_var
= get_var();
121 os
<< val_var
<< " = " << op
<< " i32 " << left
<< ", " << right
<< "\n";
124 std::ostream
&operator<<(std::ostream
&os
, const 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";
129 std::ostream
&operator<<(std::ostream
&os
, const Statement
&x
) {
130 return os
<< x
.assignment();
132 std::ostream
&operator<<(std::ostream
&os
, const StatementSeq
&x
) {
133 for (auto &st
: x
.statements()) {
138 void NestedLoopToString(std::ostream
&os
, const 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"
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"
153 << "%inner_ct = phi i64 [0, %inner_loop_start], [%i_ct_new, %inner_loop]\n";
156 os
<< x
.inner_statements();
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"
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";
168 void SingleLoopToString(std::ostream
&os
, const 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"
174 << "br label %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";
187 std::ostream
&operator<<(std::ostream
&os
, const LoopFunction
&x
) {
188 if (x
.has_inner_statements())
189 NestedLoopToString(os
, x
);
191 SingleLoopToString(os
, x
);
195 // ---------------------------------
197 std::string
LoopFunctionToLLVMString(const LoopFunction
&input
) {
198 std::ostringstream os
;
202 std::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
);
209 } // namespace clang_fuzzer