//===- llvm/unittest/IR/BasicBlockTest.cpp - BasicBlock unit tests --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DebugInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/NoFolder.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/SourceMgr.h" #include "gmock/gmock-matchers.h" #include "gtest/gtest.h" #include <memory> usingnamespacellvm; static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { … } namespace { // We can occasionally moveAfter an instruction so that it moves to the // position that it already resides at. This is fine -- but gets complicated // with dbg.value intrinsics. By moving an instruction, we can end up changing // nothing but the location of debug-info intrinsics. That has to be modelled // by DbgVariableRecords, the dbg.value replacement. TEST(BasicBlockDbgInfoTest, InsertAfterSelf) { … } TEST(BasicBlockDbgInfoTest, SplitBasicBlockBefore) { … } TEST(BasicBlockDbgInfoTest, MarkerOperations) { … } TEST(BasicBlockDbgInfoTest, HeadBitOperations) { … } TEST(BasicBlockDbgInfoTest, InstrDbgAccess) { … } /* Let's recall the big illustration from BasicBlock::spliceDebugInfo: Dest | this-block: A----A----A ====A----A----A----A---A---A Src-block ++++B---B---B---B:::C | | First Last in all it's glory. Depending on the bit-configurations for the iterator head / tail bits on the three named iterators, there are eight ways for a splice to occur. To save the amount of thinking needed to pack this into one unit test, just test the same IR eight times with difference splices. The IR shall be thus: define i16 @f(i16 %a) !dbg !6 { entry: call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11 %b = add i16 %a, 1, !dbg !11 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11 br label %exit, !dbg !11 exit: call void @llvm.dbg.value(metadata i16 0, metadata !9, metadata !DIExpression()), !dbg !11 %c = add i16 %b, 1, !dbg !11 ret i16 0, !dbg !11 } The iterators will be: Dest: exit block, "c" instruction. First: entry block, "b" instruction. Last: entry block, branch instruction. The numbered configurations will be: | Dest-Head | First-Head | Last-tail ----+----------------+----------------+------------ 0 | false | false | false 1 | true | false | false 2 | false | true | false 3 | true | true | false 4 | false | false | true 5 | true | false | true 6 | false | true | true 7 | true | true | true Each numbered test scenario will also have a short explanation indicating what this bit configuration represents. */ static const std::string SpliceTestIR = …; class DbgSpliceTest : public ::testing::Test { … }; TEST_F(DbgSpliceTest, DbgSpliceTest0) { … } TEST_F(DbgSpliceTest, DbgSpliceTest1) { … } TEST_F(DbgSpliceTest, DbgSpliceTest2) { … } TEST_F(DbgSpliceTest, DbgSpliceTest3) { … } TEST_F(DbgSpliceTest, DbgSpliceTest4) { … } TEST_F(DbgSpliceTest, DbgSpliceTest5) { … } TEST_F(DbgSpliceTest, DbgSpliceTest6) { … } TEST_F(DbgSpliceTest, DbgSpliceTest7) { … } // But wait, there's more! What if you splice a range that is empty, but // implicitly contains debug-info? In the dbg.value design for debug-info, // this would be an explicit range, but in DbgVariableRecord debug-info, it // isn't. Check that if we try to do that, with differing head-bit values, that // DbgVariableRecords are transferred. // Test with empty transfers to Dest, with head bit set and not set. TEST_F(DbgSpliceTest, DbgSpliceEmpty0) { … } TEST_F(DbgSpliceTest, DbgSpliceEmpty1) { … } // If we splice new instructions into a block with trailing DbgVariableRecords, // then the trailing DbgVariableRecords should get flushed back out. TEST(BasicBlockDbgInfoTest, DbgSpliceTrailing) { … } // When we remove instructions from the program, adjacent DbgVariableRecords // coalesce together into one DbgMarker. In "old" dbg.value mode you could // re-insert the removed instruction back into the middle of a sequence of // dbg.values. Test that this can be replicated correctly by DbgVariableRecords TEST(BasicBlockDbgInfoTest, RemoveInstAndReinsert) { … } // Test instruction removal and re-insertion, this time with one // DbgVariableRecord that should hop up one instruction. TEST(BasicBlockDbgInfoTest, RemoveInstAndReinsertForOneDbgVariableRecord) { … } // Similar to the above, what if we splice into an empty block with debug-info, // with debug-info at the start of the moving range, that we intend to be // transferred. The dbg.value of %a should remain at the start, but come ahead // of the i16 0 dbg.value. TEST(BasicBlockDbgInfoTest, DbgSpliceToEmpty1) { … } // Similar test again, but this time: splice the contents of exit into entry, // with the intention of leaving the first dbg.value (i16 0) behind. TEST(BasicBlockDbgInfoTest, DbgSpliceToEmpty2) { … } // What if we moveBefore end() -- there might be no debug-info there, in which // case we shouldn't crash. TEST(BasicBlockDbgInfoTest, DbgMoveToEnd) { … } TEST(BasicBlockDbgInfoTest, CloneTrailingRecordsToEmptyBlock) { … } } // End anonymous namespace.