klee
IntrinsicCleaner.cpp
Go to the documentation of this file.
1//===-- IntrinsicCleaner.cpp ----------------------------------------------===//
2//
3// The KLEE Symbolic Virtual Machine
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Passes.h"
11
12#include "klee/Config/Version.h"
14#include "llvm/Analysis/MemoryBuiltins.h"
15#include "llvm/Analysis/ConstantFolding.h"
16#include "llvm/IR/Constants.h"
17#include "llvm/IR/DerivedTypes.h"
18#include "llvm/IR/Function.h"
19#include "llvm/IR/IRBuilder.h"
20#include "llvm/IR/InstrTypes.h"
21#include "llvm/IR/Instruction.h"
22#include "llvm/IR/Instructions.h"
23#include "llvm/IR/IntrinsicInst.h"
24#if LLVM_VERSION_CODE >= LLVM_VERSION(10, 0)
25#include "llvm/IR/IntrinsicsX86.h"
26#endif
27#include "llvm/IR/Module.h"
28#include "llvm/IR/Type.h"
29#include "llvm/Pass.h"
30#include "llvm/Transforms/Scalar.h"
31#include "llvm/Transforms/Utils/BasicBlockUtils.h"
32
33using namespace llvm;
34
35namespace klee {
36
38
40 bool dirty = false;
41 for (Module::iterator f = M.begin(), fe = M.end(); f != fe; ++f)
42 for (Function::iterator b = f->begin(), be = f->end(); b != be; ++b)
43 dirty |= runOnBasicBlock(*b, M);
44
45 if (Function *Declare = M.getFunction("llvm.trap")) {
46 Declare->eraseFromParent();
47 dirty = true;
48 }
49 return dirty;
50}
51
52bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b, Module &M) {
53 bool dirty = false;
54 LLVMContext &ctx = M.getContext();
55
56 unsigned WordSize = DataLayout.getPointerSizeInBits() / 8;
57 for (BasicBlock::iterator i = b.begin(), ie = b.end(); i != ie;) {
58 IntrinsicInst *ii = dyn_cast<IntrinsicInst>(&*i);
59 // increment now since deletion of instructions makes iterator invalid.
60 ++i;
61 if (ii) {
62 if (isa<DbgInfoIntrinsic>(ii))
63 continue;
64
65 switch (ii->getIntrinsicID()) {
66 case Intrinsic::vastart:
67 case Intrinsic::vaend:
68 case Intrinsic::fabs:
69#if LLVM_VERSION_CODE >= LLVM_VERSION(7, 0)
70 case Intrinsic::fshr:
71 case Intrinsic::fshl:
72#endif
73#if LLVM_VERSION_CODE >= LLVM_VERSION(12, 0)
74 case Intrinsic::abs:
75 case Intrinsic::smax:
76 case Intrinsic::smin:
77 case Intrinsic::umax:
78 case Intrinsic::umin:
79#endif
80 break;
81
82 // Lower vacopy so that object resolution etc is handled by
83 // normal instructions.
84 //
85 // FIXME: This is much more target dependent than just the word size,
86 // however this works for x86-32 and x86-64.
87 case Intrinsic::vacopy: { // (dst, src) -> *((i8**) dst) = *((i8**) src)
88 llvm::IRBuilder<> Builder(ii);
89 Value *dst = ii->getArgOperand(0);
90 Value *src = ii->getArgOperand(1);
91
92 if (WordSize == 4) {
93 Type *i8pp = PointerType::getUnqual(
94 PointerType::getUnqual(Type::getInt8Ty(ctx)));
95 auto castedDst =
96 Builder.CreatePointerCast(dst, i8pp, "vacopy.cast.dst");
97 auto castedSrc =
98 Builder.CreatePointerCast(src, i8pp, "vacopy.cast.src");
99 auto load =
100 Builder.CreateLoad(castedSrc->getType()->getPointerElementType(),
101 castedSrc, "vacopy.read");
102 Builder.CreateStore(load, castedDst, false /* isVolatile */);
103 } else {
104 assert(WordSize == 8 && "Invalid word size!");
105 Type *i64p = PointerType::getUnqual(Type::getInt64Ty(ctx));
106 auto pDst = Builder.CreatePointerCast(dst, i64p, "vacopy.cast.dst");
107 auto pSrc = Builder.CreatePointerCast(src, i64p, "vacopy.cast.src");
108
109 auto pSrcType = pSrc->getType()->getPointerElementType();
110 auto pDstType = pDst->getType()->getPointerElementType();
111
112 auto val = Builder.CreateLoad(pSrcType, pSrc);
113 Builder.CreateStore(val, pDst, ii);
114
115 auto off = ConstantInt::get(Type::getInt64Ty(ctx), 1);
116 pDst = Builder.CreateGEP(pDstType, pDst, off);
117 pSrc = Builder.CreateGEP(pSrcType, pSrc, off);
118 val = Builder.CreateLoad(pSrcType, pSrc);
119 Builder.CreateStore(val, pDst);
120 pDst = Builder.CreateGEP(pDstType, pDst, off);
121 pSrc = Builder.CreateGEP(pSrcType, pSrc, off);
122 val = Builder.CreateLoad(pSrcType, pSrc);
123 Builder.CreateStore(val, pDst);
124 }
125 ii->eraseFromParent();
126 dirty = true;
127 break;
128 }
129
130 case Intrinsic::sadd_with_overflow:
131 case Intrinsic::ssub_with_overflow:
132 case Intrinsic::smul_with_overflow:
133 case Intrinsic::uadd_with_overflow:
134 case Intrinsic::usub_with_overflow:
135 case Intrinsic::umul_with_overflow: {
136 IRBuilder<> builder(ii->getParent(), ii->getIterator());
137
138 Value *op1 = ii->getArgOperand(0);
139 Value *op2 = ii->getArgOperand(1);
140
141 Value *result = 0;
142 Value *result_ext = 0;
143 Value *overflow = 0;
144
145 unsigned int bw = op1->getType()->getPrimitiveSizeInBits();
146 unsigned int bw2 = op1->getType()->getPrimitiveSizeInBits() * 2;
147
148 if ((ii->getIntrinsicID() == Intrinsic::uadd_with_overflow) ||
149 (ii->getIntrinsicID() == Intrinsic::usub_with_overflow) ||
150 (ii->getIntrinsicID() == Intrinsic::umul_with_overflow)) {
151
152 Value *op1ext =
153 builder.CreateZExt(op1, IntegerType::get(M.getContext(), bw2));
154 Value *op2ext =
155 builder.CreateZExt(op2, IntegerType::get(M.getContext(), bw2));
156 Value *int_max_s =
157 ConstantInt::get(op1->getType(), APInt::getMaxValue(bw));
158 Value *int_max = builder.CreateZExt(
159 int_max_s, IntegerType::get(M.getContext(), bw2));
160
161 if (ii->getIntrinsicID() == Intrinsic::uadd_with_overflow) {
162 result_ext = builder.CreateAdd(op1ext, op2ext);
163 } else if (ii->getIntrinsicID() == Intrinsic::usub_with_overflow) {
164 result_ext = builder.CreateSub(op1ext, op2ext);
165 } else if (ii->getIntrinsicID() == Intrinsic::umul_with_overflow) {
166 result_ext = builder.CreateMul(op1ext, op2ext);
167 }
168 overflow = builder.CreateICmpUGT(result_ext, int_max);
169
170 } else if ((ii->getIntrinsicID() == Intrinsic::sadd_with_overflow) ||
171 (ii->getIntrinsicID() == Intrinsic::ssub_with_overflow) ||
172 (ii->getIntrinsicID() == Intrinsic::smul_with_overflow)) {
173
174 Value *op1ext =
175 builder.CreateSExt(op1, IntegerType::get(M.getContext(), bw2));
176 Value *op2ext =
177 builder.CreateSExt(op2, IntegerType::get(M.getContext(), bw2));
178 Value *int_max_s =
179 ConstantInt::get(op1->getType(), APInt::getSignedMaxValue(bw));
180 Value *int_min_s =
181 ConstantInt::get(op1->getType(), APInt::getSignedMinValue(bw));
182 Value *int_max = builder.CreateSExt(
183 int_max_s, IntegerType::get(M.getContext(), bw2));
184 Value *int_min = builder.CreateSExt(
185 int_min_s, IntegerType::get(M.getContext(), bw2));
186
187 if (ii->getIntrinsicID() == Intrinsic::sadd_with_overflow) {
188 result_ext = builder.CreateAdd(op1ext, op2ext);
189 } else if (ii->getIntrinsicID() == Intrinsic::ssub_with_overflow) {
190 result_ext = builder.CreateSub(op1ext, op2ext);
191 } else if (ii->getIntrinsicID() == Intrinsic::smul_with_overflow) {
192 result_ext = builder.CreateMul(op1ext, op2ext);
193 }
194 overflow =
195 builder.CreateOr(builder.CreateICmpSGT(result_ext, int_max),
196 builder.CreateICmpSLT(result_ext, int_min));
197 }
198
199 // This trunc cound be replaced by a more general trunc replacement
200 // that allows to detect also undefined behavior in assignments or
201 // overflow in operation with integers whose dimension is smaller than
202 // int's dimension, e.g.
203 // uint8_t = uint8_t + uint8_t;
204 // if one desires the wrapping should write
205 // uint8_t = (uint8_t + uint8_t) & 0xFF;
206 // before this, must check if it has side effects on other operations
207 result = builder.CreateTrunc(result_ext, op1->getType());
208 Value *resultStruct = builder.CreateInsertValue(
209 UndefValue::get(ii->getType()), result, 0);
210 resultStruct = builder.CreateInsertValue(resultStruct, overflow, 1);
211
212 ii->replaceAllUsesWith(resultStruct);
213 ii->eraseFromParent();
214 dirty = true;
215 break;
216 }
217#if LLVM_VERSION_CODE >= LLVM_VERSION(8, 0)
218 case Intrinsic::sadd_sat:
219 case Intrinsic::ssub_sat:
220 case Intrinsic::uadd_sat:
221 case Intrinsic::usub_sat: {
222 IRBuilder<> builder(ii);
223
224 Value *op1 = ii->getArgOperand(0);
225 Value *op2 = ii->getArgOperand(1);
226
227 unsigned int bw = op1->getType()->getPrimitiveSizeInBits();
228 assert(bw == op2->getType()->getPrimitiveSizeInBits());
229
230 Value *overflow = nullptr;
231 Value *result = nullptr;
232 Value *saturated = nullptr;
233 switch(ii->getIntrinsicID()) {
234 case Intrinsic::usub_sat:
235 result = builder.CreateSub(op1, op2);
236 overflow = builder.CreateICmpULT(op1, op2); // a < b => a - b < 0
237 saturated = ConstantInt::get(ctx, APInt(bw, 0));
238 break;
239 case Intrinsic::uadd_sat:
240 result = builder.CreateAdd(op1, op2);
241 overflow = builder.CreateICmpULT(result, op1); // a + b < a
242 saturated = ConstantInt::get(ctx, APInt::getMaxValue(bw));
243 break;
244 case Intrinsic::ssub_sat:
245 case Intrinsic::sadd_sat: {
246 if (ii->getIntrinsicID() == Intrinsic::ssub_sat) {
247 result = builder.CreateSub(op1, op2);
248 } else {
249 result = builder.CreateAdd(op1, op2);
250 }
251 ConstantInt *zero = ConstantInt::get(ctx, APInt(bw, 0));
252 ConstantInt *smin = ConstantInt::get(ctx, APInt::getSignedMinValue(bw));
253 ConstantInt *smax = ConstantInt::get(ctx, APInt::getSignedMaxValue(bw));
254
255 Value *sign1 = builder.CreateICmpSLT(op1, zero);
256 Value *sign2 = builder.CreateICmpSLT(op2, zero);
257 Value *signR = builder.CreateICmpSLT(result, zero);
258
259 if (ii->getIntrinsicID() == Intrinsic::ssub_sat) {
260 saturated = builder.CreateSelect(sign2, smax, smin);
261 } else {
262 saturated = builder.CreateSelect(sign2, smin, smax);
263 }
264
265 // The sign of the result differs from the sign of the first operand
266 overflow = builder.CreateXor(sign1, signR);
267 if (ii->getIntrinsicID() == Intrinsic::ssub_sat) {
268 // AND the signs of the operands differ
269 overflow = builder.CreateAnd(overflow, builder.CreateXor(sign1, sign2));
270 } else {
271 // AND the signs of the operands are the same
272 overflow = builder.CreateAnd(overflow, builder.CreateNot(builder.CreateXor(sign1, sign2)));
273 }
274 break;
275 }
276 default: ;
277 }
278
279 result = builder.CreateSelect(overflow, saturated, result);
280 ii->replaceAllUsesWith(result);
281 ii->eraseFromParent();
282 dirty = true;
283 break;
284 }
285#endif
286
287 case Intrinsic::trap: {
288 // Intrinsic instruction "llvm.trap" found. Directly lower it to
289 // a call of the abort() function.
290 auto C = M.getOrInsertFunction("abort", Type::getVoidTy(ctx));
291#if LLVM_VERSION_CODE >= LLVM_VERSION(9, 0)
292 if (auto *F = dyn_cast<Function>(C.getCallee())) {
293#else
294 if (auto *F = dyn_cast<Function>(C)) {
295#endif
296 F->setDoesNotReturn();
297 F->setDoesNotThrow();
298 }
299
300 llvm::IRBuilder<> Builder(ii);
301 Builder.CreateCall(C);
302 Builder.CreateUnreachable();
303
304 i = ii->eraseFromParent();
305
306 // check if the instruction after the one we just replaced is not the
307 // end of the basic block and if it is not (i.e. it is a valid
308 // instruction), delete it and all remaining because the cleaner just
309 // introduced a terminating instruction (unreachable) otherwise llvm will
310 // assert in Verifier::visitTerminatorInstr
311 while (i != ie) { // i was already incremented above.
312 i = i->eraseFromParent();
313 }
314
315 dirty = true;
316 break;
317 }
318 case Intrinsic::objectsize: {
319 // Lower the call to a concrete value
320 auto replacement = llvm::lowerObjectSizeCall(ii, DataLayout, nullptr,
321 /*MustSucceed=*/true);
322 ii->replaceAllUsesWith(replacement);
323 ii->eraseFromParent();
324 dirty = true;
325 break;
326 }
327#if LLVM_VERSION_CODE >= LLVM_VERSION(8, 0)
328 case Intrinsic::is_constant: {
329 if(auto* constant = llvm::ConstantFoldInstruction(ii, ii->getModule()->getDataLayout()))
330 ii->replaceAllUsesWith(constant);
331 else
332 ii->replaceAllUsesWith(ConstantInt::getFalse(ii->getType()));
333 ii->eraseFromParent();
334 dirty = true;
335 break;
336 }
337#endif
338
339 // The following intrinsics are currently handled by LowerIntrinsicCall
340 // (Invoking LowerIntrinsicCall with any intrinsics not on this
341 // list throws an exception.)
342 case Intrinsic::addressofreturnaddress:
343 case Intrinsic::annotation:
344 case Intrinsic::assume:
345 case Intrinsic::bswap:
346 case Intrinsic::ceil:
347 case Intrinsic::copysign:
348 case Intrinsic::cos:
349 case Intrinsic::ctlz:
350 case Intrinsic::ctpop:
351 case Intrinsic::cttz:
352 case Intrinsic::dbg_declare:
353#if LLVM_VERSION_CODE >= LLVM_VERSION(7, 0)
354 case Intrinsic::dbg_label:
355#endif
356#ifndef SUPPORT_KLEE_EH_CXX
357 case Intrinsic::eh_typeid_for:
358#endif
359 case Intrinsic::exp2:
360 case Intrinsic::exp:
361 case Intrinsic::expect:
362 case Intrinsic::floor:
363 case Intrinsic::flt_rounds:
364 case Intrinsic::frameaddress:
365 case Intrinsic::get_dynamic_area_offset:
366 case Intrinsic::invariant_end:
367 case Intrinsic::invariant_start:
368 case Intrinsic::lifetime_end:
369 case Intrinsic::lifetime_start:
370 case Intrinsic::log10:
371 case Intrinsic::log2:
372 case Intrinsic::log:
373 case Intrinsic::memcpy:
374 case Intrinsic::memmove:
375 case Intrinsic::memset:
376 case Intrinsic::not_intrinsic:
377 case Intrinsic::pcmarker:
378 case Intrinsic::pow:
379 case Intrinsic::prefetch:
380 case Intrinsic::ptr_annotation:
381 case Intrinsic::readcyclecounter:
382 case Intrinsic::returnaddress:
383 case Intrinsic::round:
384#if LLVM_VERSION_CODE >= LLVM_VERSION(11, 0)
385 case Intrinsic::roundeven:
386#endif
387 case Intrinsic::sin:
388 case Intrinsic::sqrt:
389 case Intrinsic::stackrestore:
390 case Intrinsic::stacksave:
391 case Intrinsic::trunc:
392 case Intrinsic::var_annotation:
393 IL->LowerIntrinsicCall(ii);
394 dirty = true;
395 break;
396
397#ifdef SUPPORT_KLEE_EH_CXX
398 case Intrinsic::eh_typeid_for: {
399 // Don't lower this, we need it for exception handling
400 break;
401 }
402#endif
403
404 // Warn about any unrecognized intrinsics.
405 default: {
406 const Function *Callee = ii->getCalledFunction();
407 llvm::StringRef name = Callee->getName();
408 klee_warning_once((void*)Callee, "unsupported intrinsic %.*s", (int)name.size(), name.data());
409 break;
410 }
411 }
412 }
413 }
414
415 return dirty;
416}
417} // namespace klee
bool runOnModule(llvm::Module &M) override
const llvm::DataLayout & DataLayout
Definition: Passes.h:60
bool runOnBasicBlock(llvm::BasicBlock &b, llvm::Module &M)
llvm::IntrinsicLowering * IL
Definition: Passes.h:61
uint64_t trunc(uint64_t l, unsigned outWidth, unsigned inWidth)
Definition: main.cpp:291
void void void void klee_warning_once(const void *id, const char *msg,...) __attribute__((format(printf