Fabcoin Core  0.16.2
P2P Digital Currency
Arith256.cpp
Go to the documentation of this file.
1 #include "Arith256.h"
2 
3 #include <iostream>
4 #include <iomanip>
5 
7 #include <llvm/IR/Module.h>
8 #include <llvm/IR/IntrinsicInst.h>
10 
11 #include "Type.h"
12 #include "Endianness.h"
13 #include "Utils.h"
14 
15 namespace dev
16 {
17 namespace eth
18 {
19 namespace jit
20 {
21 
23  CompilerHelper(_builder)
24 {}
25 
26 void Arith256::debug(llvm::Value* _value, char _c, llvm::Module& _module, IRBuilder& _builder)
27 {
28  static const auto funcName = "debug";
29  auto func = _module.getFunction(funcName);
30  if (!func)
31  func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {Type::Word, _builder.getInt8Ty()}, false), llvm::Function::ExternalLinkage, funcName, &_module);
32 
33  _builder.CreateCall(func, {_builder.CreateZExtOrTrunc(_value, Type::Word), _builder.getInt8(_c)});
34 }
35 
36 namespace
37 {
38 llvm::Function* createUDivRemFunc(llvm::Type* _type, llvm::Module& _module, char const* _funcName)
39 {
40  // Based of "Improved shift divisor algorithm" from "Software Integer Division" by Microsoft Research
41  // The following algorithm also handles divisor of value 0 returning 0 for both quotient and remainder
42 
43  auto retType = llvm::VectorType::get(_type, 2);
44  auto func = llvm::Function::Create(llvm::FunctionType::get(retType, {_type, _type}, false), llvm::Function::PrivateLinkage, _funcName, &_module);
45  func->setDoesNotThrow();
46  func->setDoesNotAccessMemory();
47 
48  auto zero = llvm::ConstantInt::get(_type, 0);
49  auto one = llvm::ConstantInt::get(_type, 1);
50 
51  auto iter = func->arg_begin();
52  llvm::Argument* x = &(*iter++);
53  x->setName("x");
54  llvm::Argument* y = &(*iter);
55  y->setName("y");
56 
57  auto entryBB = llvm::BasicBlock::Create(_module.getContext(), "Entry", func);
58  auto mainBB = llvm::BasicBlock::Create(_module.getContext(), "Main", func);
59  auto loopBB = llvm::BasicBlock::Create(_module.getContext(), "Loop", func);
60  auto continueBB = llvm::BasicBlock::Create(_module.getContext(), "Continue", func);
61  auto returnBB = llvm::BasicBlock::Create(_module.getContext(), "Return", func);
62 
63  auto builder = IRBuilder{entryBB};
64  auto yLEx = builder.CreateICmpULE(y, x);
65  auto r0 = x;
66  builder.CreateCondBr(yLEx, mainBB, returnBB);
67 
68  builder.SetInsertPoint(mainBB);
69  auto ctlzIntr = llvm::Intrinsic::getDeclaration(&_module, llvm::Intrinsic::ctlz, _type);
70  // both y and r are non-zero
71  auto yLz = builder.CreateCall(ctlzIntr, {y, builder.getInt1(true)}, "y.lz");
72  auto rLz = builder.CreateCall(ctlzIntr, {r0, builder.getInt1(true)}, "r.lz");
73  auto i0 = builder.CreateNUWSub(yLz, rLz, "i0");
74  auto y0 = builder.CreateShl(y, i0);
75  builder.CreateBr(loopBB);
76 
77  builder.SetInsertPoint(loopBB);
78  auto yPhi = builder.CreatePHI(_type, 2, "y.phi");
79  auto rPhi = builder.CreatePHI(_type, 2, "r.phi");
80  auto iPhi = builder.CreatePHI(_type, 2, "i.phi");
81  auto qPhi = builder.CreatePHI(_type, 2, "q.phi");
82  auto rUpdate = builder.CreateNUWSub(rPhi, yPhi);
83  auto qUpdate = builder.CreateOr(qPhi, one); // q += 1, q lowest bit is 0
84  auto rGEy = builder.CreateICmpUGE(rPhi, yPhi);
85  auto r1 = builder.CreateSelect(rGEy, rUpdate, rPhi, "r1");
86  auto q1 = builder.CreateSelect(rGEy, qUpdate, qPhi, "q");
87  auto iZero = builder.CreateICmpEQ(iPhi, zero);
88  builder.CreateCondBr(iZero, returnBB, continueBB);
89 
90  builder.SetInsertPoint(continueBB);
91  auto i2 = builder.CreateNUWSub(iPhi, one);
92  auto q2 = builder.CreateShl(q1, one);
93  auto y2 = builder.CreateLShr(yPhi, one);
94  builder.CreateBr(loopBB);
95 
96  yPhi->addIncoming(y0, mainBB);
97  yPhi->addIncoming(y2, continueBB);
98  rPhi->addIncoming(r0, mainBB);
99  rPhi->addIncoming(r1, continueBB);
100  iPhi->addIncoming(i0, mainBB);
101  iPhi->addIncoming(i2, continueBB);
102  qPhi->addIncoming(zero, mainBB);
103  qPhi->addIncoming(q2, continueBB);
104 
105  builder.SetInsertPoint(returnBB);
106  auto qRet = builder.CreatePHI(_type, 2, "q.ret");
107  qRet->addIncoming(zero, entryBB);
108  qRet->addIncoming(q1, loopBB);
109  auto rRet = builder.CreatePHI(_type, 2, "r.ret");
110  rRet->addIncoming(r0, entryBB);
111  rRet->addIncoming(r1, loopBB);
112  auto ret = builder.CreateInsertElement(llvm::UndefValue::get(retType), qRet, uint64_t(0), "ret0");
113  ret = builder.CreateInsertElement(ret, rRet, 1, "ret");
114  builder.CreateRet(ret);
115 
116  return func;
117 }
118 }
119 
120 llvm::Function* Arith256::getUDivRem256Func(llvm::Module& _module)
121 {
122  static const auto funcName = "evm.udivrem.i256";
123  if (auto func = _module.getFunction(funcName))
124  return func;
125 
126  return createUDivRemFunc(Type::Word, _module, funcName);
127 }
128 
129 llvm::Function* Arith256::getUDivRem512Func(llvm::Module& _module)
130 {
131  static const auto funcName = "evm.udivrem.i512";
132  if (auto func = _module.getFunction(funcName))
133  return func;
134 
135  return createUDivRemFunc(llvm::IntegerType::get(_module.getContext(), 512), _module, funcName);
136 }
137 
138 llvm::Function* Arith256::getUDiv256Func(llvm::Module& _module)
139 {
140  static const auto funcName = "evm.udiv.i256";
141  if (auto func = _module.getFunction(funcName))
142  return func;
143 
144  auto udivremFunc = getUDivRem256Func(_module);
145 
146  auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, {Type::Word, Type::Word}, false), llvm::Function::PrivateLinkage, funcName, &_module);
147  func->setDoesNotThrow();
148  func->setDoesNotAccessMemory();
149 
150  auto iter = func->arg_begin();
151  llvm::Argument* x = &(*iter++);
152  x->setName("x");
153  llvm::Argument* y = &(*iter);
154  y->setName("y");
155 
156  auto bb = llvm::BasicBlock::Create(_module.getContext(), {}, func);
157  auto builder = IRBuilder{bb};
158  auto udivrem = builder.CreateCall(udivremFunc, {x, y});
159  auto udiv = builder.CreateExtractElement(udivrem, uint64_t(0));
160  builder.CreateRet(udiv);
161 
162  return func;
163 }
164 
165 namespace
166 {
167 llvm::Function* createURemFunc(llvm::Type* _type, llvm::Module& _module, char const* _funcName)
168 {
169  auto udivremFunc = _type == Type::Word ? Arith256::getUDivRem256Func(_module) : Arith256::getUDivRem512Func(_module);
170 
171  auto func = llvm::Function::Create(llvm::FunctionType::get(_type, {_type, _type}, false), llvm::Function::PrivateLinkage, _funcName, &_module);
172  func->setDoesNotThrow();
173  func->setDoesNotAccessMemory();
174 
175  auto iter = func->arg_begin();
176  llvm::Argument* x = &(*iter++);
177  x->setName("x");
178  llvm::Argument* y = &(*iter);
179  y->setName("y");
180 
181  auto bb = llvm::BasicBlock::Create(_module.getContext(), {}, func);
182  auto builder = IRBuilder{bb};
183  auto udivrem = builder.CreateCall(udivremFunc, {x, y});
184  auto r = builder.CreateExtractElement(udivrem, uint64_t(1));
185  builder.CreateRet(r);
186 
187  return func;
188 }
189 }
190 
191 llvm::Function* Arith256::getURem256Func(llvm::Module& _module)
192 {
193  static const auto funcName = "evm.urem.i256";
194  if (auto func = _module.getFunction(funcName))
195  return func;
196  return createURemFunc(Type::Word, _module, funcName);
197 }
198 
199 llvm::Function* Arith256::getURem512Func(llvm::Module& _module)
200 {
201  static const auto funcName = "evm.urem.i512";
202  if (auto func = _module.getFunction(funcName))
203  return func;
204  return createURemFunc(llvm::IntegerType::get(_module.getContext(), 512), _module, funcName);
205 }
206 
207 llvm::Function* Arith256::getSDivRem256Func(llvm::Module& _module)
208 {
209  static const auto funcName = "evm.sdivrem.i256";
210  if (auto func = _module.getFunction(funcName))
211  return func;
212 
213  auto udivremFunc = getUDivRem256Func(_module);
214 
215  auto retType = llvm::VectorType::get(Type::Word, 2);
216  auto func = llvm::Function::Create(llvm::FunctionType::get(retType, {Type::Word, Type::Word}, false), llvm::Function::PrivateLinkage, funcName, &_module);
217  func->setDoesNotThrow();
218  func->setDoesNotAccessMemory();
219 
220  auto iter = func->arg_begin();
221  llvm::Argument* x = &(*iter++);
222  x->setName("x");
223  llvm::Argument* y = &(*iter);
224  y->setName("y");
225 
226  auto bb = llvm::BasicBlock::Create(_module.getContext(), "", func);
227  auto builder = IRBuilder{bb};
228  auto xIsNeg = builder.CreateICmpSLT(x, Constant::get(0));
229  auto xNeg = builder.CreateSub(Constant::get(0), x);
230  auto xAbs = builder.CreateSelect(xIsNeg, xNeg, x);
231 
232  auto yIsNeg = builder.CreateICmpSLT(y, Constant::get(0));
233  auto yNeg = builder.CreateSub(Constant::get(0), y);
234  auto yAbs = builder.CreateSelect(yIsNeg, yNeg, y);
235 
236  auto res = builder.CreateCall(udivremFunc, {xAbs, yAbs});
237  auto qAbs = builder.CreateExtractElement(res, uint64_t(0));
238  auto rAbs = builder.CreateExtractElement(res, 1);
239 
240  // the remainder has the same sign as dividend
241  auto rNeg = builder.CreateSub(Constant::get(0), rAbs);
242  auto r = builder.CreateSelect(xIsNeg, rNeg, rAbs);
243 
244  auto qNeg = builder.CreateSub(Constant::get(0), qAbs);
245  auto xyOpposite = builder.CreateXor(xIsNeg, yIsNeg);
246  auto q = builder.CreateSelect(xyOpposite, qNeg, qAbs);
247 
248  auto ret = builder.CreateInsertElement(llvm::UndefValue::get(retType), q, uint64_t(0));
249  ret = builder.CreateInsertElement(ret, r, 1);
250  builder.CreateRet(ret);
251 
252  return func;
253 }
254 
255 llvm::Function* Arith256::getSDiv256Func(llvm::Module& _module)
256 {
257  static const auto funcName = "evm.sdiv.i256";
258  if (auto func = _module.getFunction(funcName))
259  return func;
260 
261  auto sdivremFunc = getSDivRem256Func(_module);
262 
263  auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, {Type::Word, Type::Word}, false), llvm::Function::PrivateLinkage, funcName, &_module);
264  func->setDoesNotThrow();
265  func->setDoesNotAccessMemory();
266 
267  auto iter = func->arg_begin();
268  llvm::Argument* x = &(*iter++);
269  x->setName("x");
270  llvm::Argument* y = &(*iter);
271  y->setName("y");
272 
273  auto bb = llvm::BasicBlock::Create(_module.getContext(), {}, func);
274  auto builder = IRBuilder{bb};
275  auto sdivrem = builder.CreateCall(sdivremFunc, {x, y});
276  auto q = builder.CreateExtractElement(sdivrem, uint64_t(0));
277  builder.CreateRet(q);
278 
279  return func;
280 }
281 
282 llvm::Function* Arith256::getSRem256Func(llvm::Module& _module)
283 {
284  static const auto funcName = "evm.srem.i256";
285  if (auto func = _module.getFunction(funcName))
286  return func;
287 
288  auto sdivremFunc = getSDivRem256Func(_module);
289 
290  auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, {Type::Word, Type::Word}, false), llvm::Function::PrivateLinkage, funcName, &_module);
291  func->setDoesNotThrow();
292  func->setDoesNotAccessMemory();
293 
294  auto iter = func->arg_begin();
295  llvm::Argument* x = &(*iter++);
296  x->setName("x");
297  llvm::Argument* y = &(*iter);
298  y->setName("y");
299 
300  auto bb = llvm::BasicBlock::Create(_module.getContext(), {}, func);
301  auto builder = IRBuilder{bb};
302  auto sdivrem = builder.CreateCall(sdivremFunc, {x, y});
303  auto r = builder.CreateExtractElement(sdivrem, uint64_t(1));
304  builder.CreateRet(r);
305 
306  return func;
307 }
308 
309 llvm::Function* Arith256::getExpFunc()
310 {
311  if (!m_exp)
312  {
313  llvm::Type* argTypes[] = {Type::Word, Type::Word};
314  m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule());
315  m_exp->setDoesNotThrow();
316  m_exp->setDoesNotAccessMemory();
317 
318  auto iter = m_exp->arg_begin();
319  llvm::Argument* base = &(*iter++);
320  base->setName("base");
321  llvm::Argument* exponent = &(*iter);
322  exponent->setName("exponent");
323 
325 
326  // while (e != 0) {
327  // if (e % 2 == 1)
328  // r *= b;
329  // b *= b;
330  // e /= 2;
331  // }
332 
333  auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", m_exp);
334  auto headerBB = llvm::BasicBlock::Create(m_builder.getContext(), "LoopHeader", m_exp);
335  auto bodyBB = llvm::BasicBlock::Create(m_builder.getContext(), "LoopBody", m_exp);
336  auto updateBB = llvm::BasicBlock::Create(m_builder.getContext(), "ResultUpdate", m_exp);
337  auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", m_exp);
338  auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp);
339 
340  m_builder.SetInsertPoint(entryBB);
341  m_builder.CreateBr(headerBB);
342 
343  m_builder.SetInsertPoint(headerBB);
344  auto r = m_builder.CreatePHI(Type::Word, 2, "r");
345  auto b = m_builder.CreatePHI(Type::Word, 2, "b");
346  auto e = m_builder.CreatePHI(Type::Word, 2, "e");
347  auto eNonZero = m_builder.CreateICmpNE(e, Constant::get(0), "e.nonzero");
348  m_builder.CreateCondBr(eNonZero, bodyBB, returnBB);
349 
350  m_builder.SetInsertPoint(bodyBB);
351  auto eOdd = m_builder.CreateICmpNE(m_builder.CreateAnd(e, Constant::get(1)), Constant::get(0), "e.isodd");
352  m_builder.CreateCondBr(eOdd, updateBB, continueBB);
353 
354  m_builder.SetInsertPoint(updateBB);
355  auto r0 = m_builder.CreateMul(r, b);
356  m_builder.CreateBr(continueBB);
357 
358  m_builder.SetInsertPoint(continueBB);
359  auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1");
360  r1->addIncoming(r, bodyBB);
361  r1->addIncoming(r0, updateBB);
362  auto b1 = m_builder.CreateMul(b, b);
363  auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1");
364  m_builder.CreateBr(headerBB);
365 
366  r->addIncoming(Constant::get(1), entryBB);
367  r->addIncoming(r1, continueBB);
368  b->addIncoming(base, entryBB);
369  b->addIncoming(b1, continueBB);
370  e->addIncoming(exponent, entryBB);
371  e->addIncoming(e1, continueBB);
372 
373  m_builder.SetInsertPoint(returnBB);
374  m_builder.CreateRet(r);
375  }
376  return m_exp;
377 }
378 
380 {
381  // while (e != 0) {
382  // if (e % 2 == 1)
383  // r *= b;
384  // b *= b;
385  // e /= 2;
386  // }
387 
388  if (auto c1 = llvm::dyn_cast<llvm::ConstantInt>(_arg1))
389  {
390  if (auto c2 = llvm::dyn_cast<llvm::ConstantInt>(_arg2))
391  {
392  auto b = c1->getValue();
393  auto e = c2->getValue();
394  auto r = llvm::APInt{256, 1};
395  while (e != 0)
396  {
397  if (e[0])
398  r *= b;
399  b *= b;
400  e = e.lshr(1);
401  }
402  return Constant::get(r);
403  }
404  }
405 
406  return m_builder.CreateCall(getExpFunc(), {_arg1, _arg2});
407 }
408 
409 }
410 }
411 }
412 
413 extern "C"
414 {
415  EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z)
416  {
417  DLOG(JIT) << "DEBUG " << std::dec << z << ": " //<< d << c << b << a
418  << " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n";
419  }
420 }
static llvm::Function * getUDiv256Func(llvm::Module &_module)
Definition: Arith256.cpp:138
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
llvm::Module * getModule()
Reference to the IR module being compiled.
static llvm::Function * getSDivRem256Func(llvm::Module &_module)
Definition: Arith256.cpp:207
static llvm::Type * Void
Definition: Type.h:32
#define DLOG(CHANNEL)
Definition: Utils.h:18
#define c(i)
static llvm::Function * getURem256Func(llvm::Module &_module)
Definition: Arith256.cpp:191
#define EXPORT
Definition: evmjit.h:13
Base class for compiler helpers like Memory, GasMeter, etc.
static llvm::Function * getURem512Func(llvm::Module &_module)
Definition: Arith256.cpp:199
#define a(i)
#define r1(i)
#define x(i)
Config::Value_type Value
llvm::Function * getExpFunc()
Definition: Arith256.cpp:309
llvm::Value * exp(llvm::Value *_arg1, llvm::Value *_arg2)
Definition: Arith256.cpp:379
static llvm::IntegerType * Word
Definition: Type.h:21
static llvm::ConstantInt * get(int64_t _n)
Returns word-size constant.
Definition: Type.cpp:55
static llvm::Function * getUDivRem512Func(llvm::Module &_module)
Definition: Arith256.cpp:129
static llvm::Function * getUDivRem256Func(llvm::Module &_module)
Definition: Arith256.cpp:120
static llvm::Function * getSRem256Func(llvm::Module &_module)
Definition: Arith256.cpp:282
static void debug(llvm::Value *_value, char _c, llvm::Module &_module, IRBuilder &_builder)
Definition: Arith256.cpp:26
llvm::Function * m_exp
Definition: Arith256.h:33
#define b(i, j)
static llvm::Function * getSDiv256Func(llvm::Module &_module)
Definition: Arith256.cpp:255
Arith256(IRBuilder &_builder)
Definition: Arith256.cpp:22
#define e(i)
Definition: sha.cpp:733
IRBuilder & m_builder
Reference to parent compiler IR builder.
#define d(i)
Definition: sha.cpp:732
#define z(i)
llvm::IRBuilder<> IRBuilder