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