xref: /llvm-project/llvm/test/DebugInfo/COFF/jump-table.ll (revision d53425e2a33a0ff7336c86d3f668b1855c47a6de)
1; REQUIRES: arm-registered-target
2; REQUIRES: aarch64-registered-target
3; REQUIRES: x86-registered-target
4; RUN: llc -mtriple=i686-windows < %s | FileCheck %s --check-prefixes=CHECK,I686,NOTA32
5; RUN: llc -mtriple=x86_64-windows < %s | FileCheck %s --check-prefixes=CHECK,X64,NOTA32
6; RUN: llc -mtriple=aarch64-windows -aarch64-min-jump-table-entries=4 < %s | FileCheck %s --check-prefixes=CHECK,A64,NOTA32
7; RUN: llc -mtriple=thumbv7a-windows < %s | FileCheck %s --check-prefixes=CHECK,A32
8; RUN: llc -mtriple=x86_64-windows -filetype=obj < %s | llvm-readobj - --codeview | FileCheck %s --check-prefixes=CV
9
10; Generated by clang++ -S -c -std=c++11 -emit-llvm -g from the following C++11 source:
11; extern "C" void f1();
12; extern "C" void f2();
13; extern "C" void f3();
14; extern "C" void f4();
15; extern "C" void f5();
16; extern "C" void func(int i){
17;     switch (i) {
18;         case 0: f1(); break;
19;         case 1: f2(); break;
20;         case 2: f3(); break;
21;         case 3: f4(); break;
22;     }
23;     switch (i) {
24;         case 1: f2(); break;
25;         case 2: f3(); break;
26;         case 3: f4(); break;
27;         case 4: f5(); break;
28;         case 5: f1(); break;
29;     }
30; }
31
32; i686 entries are absolute addresses (Base = 0, SwitchType = Pointer).
33; x86_64 entries are fixed-size and relative to the jump table (Base = Table,
34;   SwitchType = Int32).
35; aarch64 entries are variable-sized and relative to the first entry's BB if
36;   compressed (Base = Branch+0x4, SwitchType = UInt8ShiftLeft/UInt16ShiftLeft)
37;   otherwise relative to the ADR instruction (Base = Branch-0xc, SwitchType =
38;   Int32).
39; thumbv7a entries are either absolute addresses (Base = 0, SwitchType =
40;   Pointer) OR variable-sized and relative to *after* the branch instruction
41;   (Base = Branch+0x4, SwitchType = UInt8ShiftLeft/UInt16ShiftLeft/UInt32) but
42;   there appears to be a bug where the offsets are always 0.
43
44; Verify branch labels match what's in the CodeView
45; X64:            .Ltmp1:
46; X64-NEXT:       jmpq    *%{{.*}}
47; X64:            .Ltmp4:
48; X64-NEXT:       jmpq    *%{{.*}}
49; A32:            .LCPI0_0:
50; A32-NEXT        add     pc, r{{.*}}
51; NOTE: thumbv7a places the jump tables just after the branch, so verify the other branch below
52; A64:            .Ltmp1:
53; A64-NEXT:       br      x{{.*}}
54; A64:            .Ltmp4:
55; A64-NEXT:       br      x{{.*}}
56
57; Verify jump table have the same entry size, base offset and shift as what's in the CodeView
58; CHECK:          {{\.?}}LJTI0_0:
59; I686-NEXT:      .long   LBB0_[[#]]
60; X64-NEXT:       .long   .LBB0_[[#]]-.LJTI0_0
61; A32-NEXT:       .byte   (($MBB0_[[#]])-(.LCPI0_0+4))/2
62; A64-NEXT:       .byte   (.LBB0_[[FIRSTBLOCK:[0-9]+]]-.LBB0_[[FIRSTBLOCK]])>>2
63; NOTE: thumbv7a places the jump tables just after the branch, so check for the other branch now
64; A32:            .LCPI0_1:
65; A32-NEXT        add     pc, r{{.*}}
66; CHECK:          {{\.?}}LJTI0_1:
67; I686-NEXT:      .long   LBB0_[[#]]
68; X64-NEXT:       .long   .LBB0_[[#]]-.LJTI0_1
69; A32-NEXT:       .byte   (($MBB0_[[#]])-(.LCPI0_1+4))/2
70; A64-NEXT:       .byte   (.LBB0_[[SECONDBLOCK:[0-9]+]]-.LBB0_[[SECONDBLOCK]])>>2
71
72; Verify CodeView
73; CHECK:          [[INT16:\.short|\.hword]]	4441        [[COMMENT:#|//|@]] Record kind: S_ARMSWITCHTABLE
74; I686-NEXT:      .long 0                               [[COMMENT]] Base offset
75; I686-NEXT:      .short 0                              [[COMMENT]] Base section index
76; X64-NEXT:       .secrel32	.LJTI0_0                    [[COMMENT]] Base offset
77; X64-NEXT:       .secidx	.LJTI0_0                      [[COMMENT]] Base section index
78; A32-NEXT:       .secrel32	.LCPI0_0+4                  [[COMMENT]] Base offset
79; A32-NEXT:       .secidx	.LCPI0_0                      [[COMMENT]] Base section index
80; A64-NEXT:       .secrel32	.LBB0_[[FIRSTBLOCK]]        [[COMMENT]] Base offset
81; A64-NEXT:       .secidx	.LBB0_[[FIRSTBLOCK]]          [[COMMENT]] Base section index
82; I686-NEXT:      .short	6                             [[COMMENT]] Switch type
83; X64-NEXT:       .short	4                             [[COMMENT]] Switch type
84; A32-NEXT:       .short	7                             [[COMMENT]] Switch type
85; A64-NEXT:       .hword	7                             [[COMMENT]] Switch type
86; NOTA32-NEXT:    .secrel32	{{\.?}}Ltmp1                [[COMMENT]] Branch offset
87; A32-NEXT:       .secrel32	.LCPI0_0                    [[COMMENT]] Branch offset
88; CHECK-NEXT:     .secrel32	{{\.?}}LJTI0_0              [[COMMENT]] Table offset
89; NOTA32-NEXT:    .secidx	{{\.?}}Ltmp1                  [[COMMENT]] Branch section index
90; A32-NEXT:       .secidx	.LCPI0_0                      [[COMMENT]] Branch section index
91; CHECK-NEXT:     .secidx	{{\.?}}LJTI0_0                [[COMMENT]] Table section index
92; CHECK-NEXT:     [[INT32:\.long|\.word]]	4             [[COMMENT]] Entries count
93; CHECK:          [[INT16]]	4441                        [[COMMENT]] Record kind: S_ARMSWITCHTABLE
94; I686-NEXT:      .long 0                               [[COMMENT]] Base offset
95; I686-NEXT:      .short 0                              [[COMMENT]] Base section index
96; X64-NEXT:       .secrel32	.LJTI0_1                    [[COMMENT]] Base offset
97; X64-NEXT:       .secidx	.LJTI0_1                      [[COMMENT]] Base section index
98; A32-NEXT:       .secrel32	.LCPI0_1+4                  [[COMMENT]] Base offset
99; A32-NEXT:       .secidx	.LCPI0_1                      [[COMMENT]] Base section index
100; A64-NEXT:       .secrel32	.LBB0_[[SECONDBLOCK]]       [[COMMENT]] Base offset
101; A64-NEXT:       .secidx	.LBB0_[[SECONDBLOCK]]         [[COMMENT]] Base section index
102; I686-NEXT:      .short	6                             [[COMMENT]] Switch type
103; X64-NEXT:       .short	4                             [[COMMENT]] Switch type
104; A32-NEXT:       .short	7                             [[COMMENT]] Switch type
105; A64-NEXT:       .hword	7                             [[COMMENT]] Switch type
106; NOTA32-NEXT:    .secrel32	{{\.?}}Ltmp4                [[COMMENT]] Branch offset
107; A32-NEXT:       .secrel32	.LCPI0_1                    [[COMMENT]] Branch offset
108; CHECK-NEXT:     .secrel32	{{\.?}}LJTI0_1              [[COMMENT]] Table offset
109; NOTA32-NEXT:    .secidx	{{\.?}}Ltmp4                  [[COMMENT]] Branch section index
110; A32-NEXT:       .secidx	.LCPI0_1                      [[COMMENT]] Branch section index
111; CHECK-NEXT:     .secidx	{{\.?}}LJTI0_1                [[COMMENT]] Table section index
112; CHECK-NEXT:     [[INT32]]	5                           [[COMMENT]] Entries count
113; CHECK-NOT:      [[INT16]]	4441                        [[COMMENT]] Record kind: S_ARMSWITCHTABLE
114
115; Verify CodeView as dumped by llvm-readobj
116; CV:      Subsection [
117; CV:         SubSectionType: Symbols (0xF1)
118; CV:         GlobalProcIdSym {
119; CV:           DisplayName: func
120; CV-NOT:     GlobalProcIdSym
121; CV:           JumpTableSym {
122; CV-NEXT:        Kind: S_ARMSWITCHTABLE (0x1159)
123; CV-NEXT:        BaseOffset: 0x0
124; CV-NEXT:        BaseSegment: 0
125; CV-NEXT:        SwitchType: Int32 (0x4)
126; CV-NEXT:        BranchOffset: 0x23
127; CV-NEXT:        TableOffset: 0x0
128; CV-NEXT:        BranchSegment: 0
129; CV-NEXT:        TableSegment: 0
130; CV-NEXT:        EntriesCount: 4
131; CV-NEXT:      }
132; CV-NEXT:      JumpTableSym {
133; CV-NEXT:        Kind: S_ARMSWITCHTABLE (0x1159)
134; CV-NEXT:        BaseOffset: 0x10
135; CV-NEXT:        BaseSegment: 0
136; CV-NEXT:        SwitchType: Int32 (0x4)
137; CV-NEXT:        BranchOffset: 0x5A
138; CV-NEXT:        TableOffset: 0x10
139; CV-NEXT:        BranchSegment: 0
140; CV-NEXT:        TableSegment: 0
141; CV-NEXT:        EntriesCount: 5
142; CV-NEXT:      }
143; CV-NOT:       JumpTableSym {
144
145source_filename = ".\\jump-table.cpp"
146target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
147target triple = "x86_64-pc-windows-msvc19.35.32216"
148
149; Function Attrs: mustprogress noinline optnone uwtable
150define dso_local void @func(i32 noundef %0) #0 !dbg !8 {
151  %2 = alloca i32, align 4
152  store i32 %0, ptr %2, align 4
153  call void @llvm.dbg.declare(metadata ptr %2, metadata !14, metadata !DIExpression()), !dbg !15
154  %3 = load i32, ptr %2, align 4, !dbg !16
155  switch i32 %3, label %8 [
156    i32 0, label %4
157    i32 1, label %5
158    i32 2, label %6
159    i32 3, label %7
160  ], !dbg !16
161
1624:                                                ; preds = %1
163  call void @f1(), !dbg !17
164  br label %8, !dbg !17
165
1665:                                                ; preds = %1
167  call void @f2(), !dbg !19
168  br label %8, !dbg !19
169
1706:                                                ; preds = %1
171  call void @f3(), !dbg !20
172  br label %8, !dbg !20
173
1747:                                                ; preds = %1
175  call void @f4(), !dbg !21
176  br label %8, !dbg !21
177
1788:                                                ; preds = %1, %7, %6, %5, %4
179  %9 = load i32, ptr %2, align 4, !dbg !22
180  switch i32 %9, label %15 [
181    i32 1, label %10
182    i32 2, label %11
183    i32 3, label %12
184    i32 4, label %13
185    i32 5, label %14
186  ], !dbg !22
187
18810:                                               ; preds = %8
189  call void @f2(), !dbg !23
190  br label %15, !dbg !23
191
19211:                                               ; preds = %8
193  call void @f3(), !dbg !25
194  br label %15, !dbg !25
195
19612:                                               ; preds = %8
197  call void @f4(), !dbg !26
198  br label %15, !dbg !26
199
20013:                                               ; preds = %8
201  call void @f5(), !dbg !27
202  br label %15, !dbg !27
203
20414:                                               ; preds = %8
205  call void @f1(), !dbg !28
206  br label %15, !dbg !28
207
20815:                                               ; preds = %8, %14, %13, %12, %11, %10
209  ret void, !dbg !29
210}
211
212; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
213declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
214
215declare dso_local void @f1() #2
216
217declare dso_local void @f2() #2
218
219declare dso_local void @f3() #2
220
221declare dso_local void @f4() #2
222
223declare dso_local void @f5() #2
224
225attributes #0 = { mustprogress noinline optnone uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
226attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
227attributes #2 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
228
229!llvm.dbg.cu = !{!0}
230!llvm.module.flags = !{!2, !3, !4, !5, !6}
231!llvm.ident = !{!7}
232
233!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_11, file: !1, producer: "clang version 15.0.1", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
234!1 = !DIFile(filename: "jump-table.cpp", directory: "C:\\llvm", checksumkind: CSK_MD5, checksum: "35610c7104c8080f83e2bf6a02dabfc9")
235!2 = !{i32 2, !"CodeView", i32 1}
236!3 = !{i32 2, !"Debug Info Version", i32 3}
237!4 = !{i32 1, !"wchar_size", i32 2}
238!5 = !{i32 7, !"PIC Level", i32 2}
239!6 = !{i32 7, !"uwtable", i32 2}
240!7 = !{!"clang version 15.0.1"}
241!8 = distinct !DISubprogram(name: "func", scope: !9, file: !9, line: 6, type: !10, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13)
242!9 = !DIFile(filename: ".\\jump-table.cpp", directory: "C:\\llvm", checksumkind: CSK_MD5, checksum: "35610c7104c8080f83e2bf6a02dabfc9")
243!10 = !DISubroutineType(types: !11)
244!11 = !{null, !12}
245!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
246!13 = !{}
247!14 = !DILocalVariable(name: "i", arg: 1, scope: !8, file: !9, line: 6, type: !12)
248!15 = !DILocation(line: 6, scope: !8)
249!16 = !DILocation(line: 7, scope: !8)
250!17 = !DILocation(line: 8, scope: !18)
251!18 = distinct !DILexicalBlock(scope: !8, file: !9, line: 7)
252!19 = !DILocation(line: 9, scope: !18)
253!20 = !DILocation(line: 10, scope: !18)
254!21 = !DILocation(line: 11, scope: !18)
255!22 = !DILocation(line: 13, scope: !8)
256!23 = !DILocation(line: 14, scope: !24)
257!24 = distinct !DILexicalBlock(scope: !8, file: !9, line: 13)
258!25 = !DILocation(line: 15, scope: !24)
259!26 = !DILocation(line: 16, scope: !24)
260!27 = !DILocation(line: 17, scope: !24)
261!28 = !DILocation(line: 18, scope: !24)
262!29 = !DILocation(line: 20, scope: !8)
263