Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 1 | //===- llvm/tools/gollvm/unittests/BackendCore/BackendDebugEmit.cpp -----===// |
| 2 | // |
Than McIntosh | aa1ebf9 | 2018-06-20 11:07:34 -0400 | [diff] [blame] | 3 | // Copyright 2018 The Go Authors. All rights reserved. |
| 4 | // Use of this source code is governed by a BSD-style |
| 5 | // license that can be found in the LICENSE file. |
Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "TestUtils.h" |
| 10 | #include "go-llvm-backend.h" |
| 11 | #include "gtest/gtest.h" |
| 12 | |
| 13 | using namespace goBackendUnitTests; |
| 14 | |
| 15 | namespace { |
| 16 | |
| 17 | // Insure that dbg.declare is emitted for a used-defined local |
| 18 | // variable. Remark: I worry that this unit test may be too brittle |
| 19 | // (vulnerable to spurious failures if other things in the bridge are |
| 20 | // changed). Perhaps there is some other way to verify this |
| 21 | // functionality. |
| 22 | |
| 23 | TEST(BackendDebugEmit, TestSimpleDecl) { |
| 24 | FcnTestHarness h; |
| 25 | Llvm_backend *be = h.be(); |
| 26 | BFunctionType *befty = mkFuncTyp(be, L_END); |
| 27 | Bfunction *func = h.mkFunction("foo", befty); |
| 28 | |
| 29 | Btype *bu32t = be->integer_type(true, 32); |
| 30 | h.mkLocal("x", bu32t); |
| 31 | |
| 32 | const char *exp = R"RAW_RESULT( |
| 33 | define void @foo(i8* nest %nest.0) #0 { |
| 34 | entry: |
| 35 | %x = alloca i32 |
| 36 | store i32 0, i32* %x |
Cherry Zhang | fc6df5a | 2018-10-10 16:54:23 -0400 | [diff] [blame] | 37 | call void @llvm.dbg.declare(metadata i32* %x, metadata !5, |
| 38 | metadata !DIExpression()), !dbg !12 |
Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 39 | ret void |
| 40 | } |
| 41 | )RAW_RESULT"; |
| 42 | |
| 43 | bool broken = h.finish(PreserveDebugInfo); |
| 44 | EXPECT_FALSE(broken && "Module failed to verify."); |
| 45 | |
| 46 | bool isOK = h.expectValue(func->function(), exp); |
| 47 | EXPECT_TRUE(isOK && "Function does not have expected contents"); |
| 48 | } |
| 49 | |
Cherry Zhang | 1619d36 | 2017-07-25 16:48:19 -0400 | [diff] [blame] | 50 | TEST(BackendDebugEmit, TestSimpleDecl2) { |
| 51 | // Test that parameters of empty function are handled correctly. |
| 52 | FcnTestHarness h; |
| 53 | Llvm_backend *be = h.be(); |
| 54 | Btype *bi64t = be->integer_type(false, 64); |
| 55 | Btype *bst = mkBackendStruct(be, bi64t, "f1", |
| 56 | bi64t, "f2", |
| 57 | bi64t, "f3", |
| 58 | nullptr); // large struct, pass by reference |
| 59 | BFunctionType *befty = mkFuncTyp(be, L_PARM, bst, L_END); |
| 60 | Bfunction *func = h.mkFunction("foo", befty); |
| 61 | |
| 62 | // function with no code |
| 63 | |
| 64 | bool broken = h.finish(PreserveDebugInfo); |
| 65 | EXPECT_FALSE(broken && "Module failed to verify."); |
| 66 | |
| 67 | const char *exp = R"RAW_RESULT( |
| 68 | define void @foo(i8* nest %nest.0, { i64, i64, i64 }* byval %p0) #0 { |
| 69 | entry: |
Cherry Zhang | fc6df5a | 2018-10-10 16:54:23 -0400 | [diff] [blame] | 70 | call void @llvm.dbg.declare(metadata { i64, i64, i64 }* %p0, metadata !5, |
| 71 | metadata !DIExpression()), !dbg !18 |
Cherry Zhang | 1619d36 | 2017-07-25 16:48:19 -0400 | [diff] [blame] | 72 | ret void |
| 73 | } |
| 74 | )RAW_RESULT"; |
| 75 | |
| 76 | bool isOK = h.expectValue(func->function(), exp); |
| 77 | EXPECT_TRUE(isOK && "Function does not have expected contents"); |
| 78 | } |
| 79 | |
Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 80 | // This test is designed to make sure that debug meta-data generation |
| 81 | // handles corner clases like vars with zero size (empty struct). |
| 82 | |
| 83 | // working propery |
| 84 | TEST(BackendDebugEmit, MoreComplexVarDecls) { |
| 85 | |
| 86 | FcnTestHarness h; |
| 87 | Llvm_backend *be = h.be(); |
| 88 | |
| 89 | Btype *bi32t = be->integer_type(false, 32); |
| 90 | Btype *set = mkBackendStruct(be, nullptr); // struct with no fields |
| 91 | Bexpression *val10 = mkInt64Const(be, int64_t(10)); |
| 92 | Btype *beat = be->array_type(set, val10); |
Than McIntosh | 4c39d35 | 2017-05-31 11:28:28 -0400 | [diff] [blame] | 93 | Btype *bc64t = be->complex_type(64); |
| 94 | Btype *bc128t = be->complex_type(128); |
Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 95 | |
| 96 | BFunctionType *befty1 = mkFuncTyp(be, |
| 97 | L_RES, set, |
| 98 | L_PARM, set, |
| 99 | L_PARM, beat, |
| 100 | L_PARM, bi32t, |
Than McIntosh | 4c39d35 | 2017-05-31 11:28:28 -0400 | [diff] [blame] | 101 | L_PARM, bc64t, |
| 102 | L_PARM, bc128t, |
Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 103 | L_PARM, set, |
| 104 | L_PARM, beat, |
| 105 | L_END); |
| 106 | Bfunction *func = h.mkFunction("foo", befty1); |
| 107 | BFunctionType *befty2 = mkFuncTyp(be, |
| 108 | L_RES, set, |
| 109 | L_END); |
| 110 | Bfunction *func2 = mkFuncFromType(be, "bar", befty2); |
| 111 | |
| 112 | h.mkLocal("la", set); |
| 113 | h.mkLocal("lb", beat); |
| 114 | h.mkLocal("lc", bi32t); |
| 115 | |
| 116 | Location loc; |
| 117 | std::vector<Bvariable *> vlist; |
Than McIntosh | 2d09f01 | 2018-01-11 14:12:15 -0500 | [diff] [blame] | 118 | vlist.push_back(be->local_variable(func, "n1", set, nullptr, false, loc)); |
| 119 | vlist.push_back(be->local_variable(func, "n2", beat, nullptr, false, loc)); |
| 120 | vlist.push_back(be->local_variable(func, "n3", bi32t, nullptr, false, loc)); |
Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 121 | h.newBlock(&vlist); |
| 122 | |
| 123 | Bexpression *fn2 = be->function_code_expression(func2, loc); |
| 124 | std::vector<Bexpression *> noargs; |
| 125 | Bexpression *call2 = |
| 126 | be->call_expression(func2, fn2, noargs, nullptr, h.loc()); |
| 127 | h.addStmt(be->init_statement(func, vlist[0], call2)); |
| 128 | h.addStmt(be->init_statement(func, vlist[1], be->zero_expression(beat))); |
| 129 | h.addStmt(be->init_statement(func, vlist[2], be->zero_expression(bi32t))); |
| 130 | |
| 131 | // return foo(f1, f2, 4, f1, f2) |
| 132 | Bexpression *fn = be->function_code_expression(func, loc); |
| 133 | Bvariable *p0 = func->getNthParamVar(0); |
| 134 | Bvariable *p1 = func->getNthParamVar(1); |
| 135 | std::vector<Bexpression *> args; |
Than McIntosh | e6cf70f | 2017-11-14 09:16:47 -0500 | [diff] [blame] | 136 | args.push_back(be->var_expression(p0, loc)); |
| 137 | args.push_back(be->var_expression(p1, loc)); |
Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 138 | args.push_back(mkInt32Const(be, 4)); |
Than McIntosh | e6cf70f | 2017-11-14 09:16:47 -0500 | [diff] [blame] | 139 | args.push_back(be->var_expression(p0, loc)); |
| 140 | args.push_back(be->var_expression(p1, loc)); |
Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 141 | Bexpression *call = be->call_expression(func, fn, args, nullptr, h.loc()); |
| 142 | std::vector<Bexpression *> rvals; |
| 143 | rvals.push_back(call); |
| 144 | h.mkReturn(rvals); |
| 145 | |
| 146 | bool broken = h.finish(PreserveDebugInfo); |
| 147 | EXPECT_FALSE(broken && "Module failed to verify."); |
| 148 | |
| 149 | std::string fdump = repr(func->function()); |
| 150 | std::vector<std::string> tokens = tokenize(fdump); |
| 151 | unsigned declcount = 0; |
| 152 | for (auto t : tokens) |
| 153 | if (t == "@llvm.dbg.declare(metadata") |
| 154 | declcount += 1; |
| 155 | |
Than McIntosh | 4c39d35 | 2017-05-31 11:28:28 -0400 | [diff] [blame] | 156 | // seven formals and six locals => 13 var decls |
| 157 | EXPECT_EQ(declcount, 13u); |
| 158 | if (declcount != 13) |
Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 159 | std::cerr << fdump; |
| 160 | } |
| 161 | |
Cherry Zhang | 560fe66 | 2017-08-02 15:47:14 -0400 | [diff] [blame] | 162 | TEST(BackendDebugEmit, TestDeadLocalVar) { |
| 163 | // Test that dead local variable doesn't cause problem. |
| 164 | FcnTestHarness h; |
| 165 | Llvm_backend *be = h.be(); |
| 166 | BFunctionType *befty = mkFuncTyp(be, L_END); |
| 167 | Bfunction *func = h.mkFunction("foo", befty); |
| 168 | |
| 169 | h.mkReturn(std::vector<Bexpression*>{}); |
| 170 | Btype *bu32t = be->integer_type(true, 32); |
| 171 | h.mkLocal("x", bu32t); |
| 172 | |
| 173 | const char *exp = R"RAW_RESULT( |
Cherry Zhang | fc6df5a | 2018-10-10 16:54:23 -0400 | [diff] [blame] | 174 | define void @foo(i8* nest %nest.0) #0 !dbg !5 { |
Cherry Zhang | 560fe66 | 2017-08-02 15:47:14 -0400 | [diff] [blame] | 175 | entry: |
| 176 | %x = alloca i32 |
Cherry Zhang | fc6df5a | 2018-10-10 16:54:23 -0400 | [diff] [blame] | 177 | ret void, !dbg !10 |
Cherry Zhang | 560fe66 | 2017-08-02 15:47:14 -0400 | [diff] [blame] | 178 | } |
| 179 | )RAW_RESULT"; |
| 180 | |
| 181 | bool broken = h.finish(PreserveDebugInfo); |
| 182 | EXPECT_FALSE(broken && "Module failed to verify."); |
| 183 | |
| 184 | bool isOK = h.expectValue(func->function(), exp); |
| 185 | EXPECT_TRUE(isOK && "Function does not have expected contents"); |
| 186 | } |
| 187 | |
Than McIntosh | dbda009 | 2017-06-22 15:44:50 -0400 | [diff] [blame] | 188 | TEST(BackendVarTests, TestGlobalVarDebugEmit) { |
| 189 | FcnTestHarness h("foo"); |
| 190 | Llvm_backend *be = h.be(); |
| 191 | Location loc = h.loc(); |
| 192 | |
| 193 | Btype *bi32t = be->integer_type(false, 32); |
| 194 | Bvariable *g1 = |
| 195 | be->global_variable("_bar", "bar", bi32t, |
| 196 | true, /* is_external */ |
| 197 | false, /* is_hidden */ |
| 198 | false, /* unique_section */ |
| 199 | loc); |
| 200 | be->global_variable_set_init(g1, mkInt32Const(be, 101)); |
| 201 | |
| 202 | bool broken = h.finish(PreserveDebugInfo); |
| 203 | EXPECT_FALSE(broken && "Module failed to verify."); |
| 204 | |
| 205 | // This is a long way from verifying that the debug meta-data is in fact |
| 206 | // completely correct, but at least it checks that the global |
| 207 | // wasn't skipped. |
| 208 | bool ok = h.expectModuleDumpContains("!DIGlobalVariable(name: \"bar\","); |
| 209 | EXPECT_TRUE(ok); |
| 210 | |
| 211 | } |
| 212 | |
Than McIntosh | 0a5a1ff | 2018-05-21 12:54:08 -0400 | [diff] [blame] | 213 | TEST(BackendDebugEmit, TestDebugPrefixMap) { |
| 214 | |
| 215 | FcnTestHarness h; |
| 216 | Llvm_backend *be = h.be(); |
| 217 | Btype *bi64t = be->integer_type(false, 64); |
| 218 | BFunctionType *befty = mkFuncTyp(be, L_PARM, bi64t, L_RES, bi64t, L_END); |
| 219 | |
| 220 | llvm::StringRef from2("/bar"); |
| 221 | llvm::StringRef to2("/something"); |
| 222 | be->addDebugPrefix(std::make_pair(from2, to2)); |
| 223 | |
| 224 | Location loc = h.newFileLineLoc("/bar/another/barcode.go", 11); |
| 225 | Bfunction *func = h.mkFunction("bar", befty); |
| 226 | Bvariable *p0 = func->getNthParamVar(0); |
| 227 | Bexpression *vec = be->var_expression(p0, loc); |
| 228 | h.mkReturn(std::vector<Bexpression*>{vec}); |
| 229 | |
| 230 | bool broken = h.finish(PreserveDebugInfo); |
| 231 | EXPECT_FALSE(broken && "Module failed to verify."); |
| 232 | |
Than McIntosh | 0a5a1ff | 2018-05-21 12:54:08 -0400 | [diff] [blame] | 233 | // Check for remapped source file. |
| 234 | bool ok = h.expectModuleDumpContains("!DIFile(filename: \"barcode.go\", directory: \"/something/another\")"); |
| 235 | EXPECT_TRUE(ok); |
| 236 | } |
| 237 | |
Than McIntosh | 8d469d0 | 2018-05-21 13:16:16 -0400 | [diff] [blame] | 238 | TEST(BackendDebugEmit, TestFileLineDirectives) { |
| 239 | |
| 240 | FcnTestHarness h; |
| 241 | Llvm_backend *be = h.be(); |
| 242 | Btype *bi64t = be->integer_type(false, 64); |
| 243 | BFunctionType *befty = mkFuncTyp(be, L_PARM, bi64t, L_RES, bi64t, L_END); |
| 244 | Bfunction *func = h.mkFunction("bar", befty); |
| 245 | Bvariable *p0 = func->getNthParamVar(0); |
| 246 | |
| 247 | Location loc = h.newFileLineLoc("watermelon.go", 43); |
| 248 | Bexpression *vex1 = be->var_expression(p0, loc); |
| 249 | Bvariable *xv = h.mkLocal("x", bi64t, vex1); |
| 250 | |
| 251 | loc = h.newFileLineLoc("kiwifruit.go", 43); |
| 252 | Bexpression *vex2 = be->var_expression(p0, loc); |
| 253 | Bexpression *vex3 = be->var_expression(xv, loc); |
| 254 | h.mkAssign(vex2, vex3); |
| 255 | |
| 256 | loc = h.newFileLineLoc("apple.go", 11); |
| 257 | Bexpression *vex4 = be->var_expression(p0, loc); |
| 258 | h.mkReturn(std::vector<Bexpression*>{vex4}); |
| 259 | |
| 260 | bool broken = h.finish(PreserveDebugInfo); |
| 261 | EXPECT_FALSE(broken && "Module failed to verify."); |
| 262 | |
Than McIntosh | 8d469d0 | 2018-05-21 13:16:16 -0400 | [diff] [blame] | 263 | // Three of the constructs above had different files applied to them |
| 264 | // (equivalent of Go //line directive); make sure that the files |
| 265 | // appear in the meta-data. |
| 266 | bool ok = h.expectModuleDumpContains("!DIFile(filename: \"watermelon.go\", directory: \"\")"); |
| 267 | EXPECT_TRUE(ok); |
| 268 | ok = h.expectModuleDumpContains("!DIFile(filename: \"kiwifruit.go\", directory: \"\")"); |
| 269 | EXPECT_TRUE(ok); |
| 270 | ok = h.expectModuleDumpContains("!DIFile(filename: \"apple.go\", directory: \"\")"); |
| 271 | EXPECT_TRUE(ok); |
| 272 | } |
| 273 | |
Than McIntosh | 9cff07b | 2017-05-18 14:24:02 -0400 | [diff] [blame] | 274 | } |