8
8
9
9
#include " llvm/Transforms/Utils/CallPromotionUtils.h"
10
10
#include " llvm/AsmParser/Parser.h"
11
+ #include " llvm/IR/IRBuilder.h"
11
12
#include " llvm/IR/Instructions.h"
12
13
#include " llvm/IR/LLVMContext.h"
14
+ #include " llvm/IR/MDBuilder.h"
13
15
#include " llvm/IR/Module.h"
16
+ #include " llvm/IR/NoFolder.h"
14
17
#include " llvm/Support/SourceMgr.h"
15
18
#include " gtest/gtest.h"
16
19
@@ -24,6 +27,21 @@ static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
24
27
return Mod;
25
28
}
26
29
30
+ // Returns a constant representing the vtable's address point specified by the
31
+ // offset.
32
+ static Constant *getVTableAddressPointOffset (GlobalVariable *VTable,
33
+ uint32_t AddressPointOffset) {
34
+ Module &M = *VTable->getParent ();
35
+ LLVMContext &Context = M.getContext ();
36
+ assert (AddressPointOffset <
37
+ M.getDataLayout ().getTypeAllocSize (VTable->getValueType ()) &&
38
+ " Out-of-bound access" );
39
+
40
+ return ConstantExpr::getInBoundsGetElementPtr (
41
+ Type::getInt8Ty (Context), VTable,
42
+ llvm::ConstantInt::get (Type::getInt32Ty (Context), AddressPointOffset));
43
+ }
44
+
27
45
TEST (CallPromotionUtilsTest, TryPromoteCall) {
28
46
LLVMContext C;
29
47
std::unique_ptr<Module> M = parseIR (C,
@@ -368,3 +386,73 @@ declare %struct2 @_ZN4Impl3RunEv(%class.Impl* %this)
368
386
bool IsPromoted = tryPromoteCall (*CI);
369
387
EXPECT_FALSE (IsPromoted);
370
388
}
389
+
390
+ TEST (CallPromotionUtilsTest, promoteCallWithVTableCmp) {
391
+ LLVMContext C;
392
+ std::unique_ptr<Module> M = parseIR (C,
393
+ R"IR(
394
+ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
395
+ target triple = "x86_64-unknown-linux-gnu"
396
+
397
+ @_ZTV5Base1 = constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr null, ptr @_ZN5Base15func0Ev, ptr @_ZN5Base15func1Ev] }, !type !0
398
+ @_ZTV8Derived1 = constant { [4 x ptr], [3 x ptr] } { [4 x ptr] [ptr inttoptr (i64 -8 to ptr), ptr null, ptr @_ZN5Base15func0Ev, ptr @_ZN5Base15func1Ev], [3 x ptr] [ptr null, ptr null, ptr @_ZN5Base25func2Ev] }, !type !0, !type !1, !type !2
399
+ @_ZTV8Derived2 = constant { [3 x ptr], [3 x ptr], [4 x ptr] } { [3 x ptr] [ptr null, ptr null, ptr @_ZN5Base35func3Ev], [3 x ptr] [ptr inttoptr (i64 -8 to ptr), ptr null, ptr @_ZN5Base25func2Ev], [4 x ptr] [ptr inttoptr (i64 -16 to ptr), ptr null, ptr @_ZN5Base15func0Ev, ptr @_ZN5Base15func1Ev] }, !type !3, !type !4, !type !5, !type !6
400
+
401
+ define i32 @testfunc(ptr %d) {
402
+ entry:
403
+ %vtable = load ptr, ptr %d, !prof !7
404
+ %vfn = getelementptr inbounds ptr, ptr %vtable, i64 1
405
+ %0 = load ptr, ptr %vfn
406
+ %call = tail call i32 %0(ptr %d), !prof !8
407
+ ret i32 %call
408
+ }
409
+
410
+ define i32 @_ZN5Base15func1Ev(ptr %this) {
411
+ entry:
412
+ ret i32 2
413
+ }
414
+
415
+ declare i32 @_ZN5Base25func2Ev(ptr)
416
+ declare i32 @_ZN5Base15func0Ev(ptr)
417
+ declare void @_ZN5Base35func3Ev(ptr)
418
+
419
+ !0 = !{i64 16, !"_ZTS5Base1"}
420
+ !1 = !{i64 48, !"_ZTS5Base2"}
421
+ !2 = !{i64 16, !"_ZTS8Derived1"}
422
+ !3 = !{i64 64, !"_ZTS5Base1"}
423
+ !4 = !{i64 40, !"_ZTS5Base2"}
424
+ !5 = !{i64 16, !"_ZTS5Base3"}
425
+ !6 = !{i64 16, !"_ZTS8Derived2"}
426
+ !7 = !{!"VP", i32 2, i64 1600, i64 -9064381665493407289, i64 800, i64 5035968517245772950, i64 500, i64 3215870116411581797, i64 300}
427
+ !8 = !{!"VP", i32 0, i64 1600, i64 6804820478065511155, i64 1600})IR" );
428
+
429
+ Function *F = M->getFunction (" testfunc" );
430
+ CallInst *CI = dyn_cast<CallInst>(&*std::next (F->front ().rbegin ()));
431
+ ASSERT_TRUE (CI && CI->isIndirectCall ());
432
+
433
+ // Create the constant and the branch weights
434
+ SmallVector<Constant *, 3 > VTableAddressPoints;
435
+
436
+ for (auto &[VTableName, AddressPointOffset] : {std::pair{" _ZTV5Base1" , 16 },
437
+ {" _ZTV8Derived1" , 16 },
438
+ {" _ZTV8Derived2" , 64 }})
439
+ VTableAddressPoints.push_back (getVTableAddressPointOffset (
440
+ M->getGlobalVariable (VTableName), AddressPointOffset));
441
+
442
+ MDBuilder MDB (C);
443
+ MDNode *BranchWeights = MDB.createBranchWeights (1600 , 0 );
444
+
445
+ size_t OrigEntryBBSize = F->front ().size ();
446
+
447
+ LoadInst *VPtr = dyn_cast<LoadInst>(&*F->front ().begin ());
448
+
449
+ Function *Callee = M->getFunction (" _ZN5Base15func1Ev" );
450
+ // Tests that promoted direct call is returned.
451
+ CallBase &DirectCB = promoteCallWithVTableCmp (
452
+ *CI, VPtr, Callee, VTableAddressPoints, BranchWeights);
453
+ EXPECT_EQ (DirectCB.getCalledOperand (), Callee);
454
+
455
+ // Promotion inserts 3 icmp instructions and 2 or instructions, and removes
456
+ // 1 call instruction from the entry block.
457
+ EXPECT_EQ (F->front ().size (), OrigEntryBBSize + 4 );
458
+ }
0 commit comments