================
@@ -0,0 +1,127 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o
%t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o
%t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+int f(int x) {
+ static const void *tbl[] = {&&L1, &&L2};
+ goto *tbl[x];
+L1:
+ return 1;
+L2:
+ return 2;
+}
+
+// A appears twice in g's table; both occurrences are kept as indirect-branch
+// successors, matching classic codegen.
+int g(int x) {
+ static const void *tbl[] = {&&A, &&A, &&B};
+ goto *tbl[x];
+A:
+ return 1;
+B:
+ return 2;
+}
+
+// A constant label address with no indirect goto reaching it: the
indirect-goto
+// block is created but has no predecessors, so it is left poisoned.
+int h(int x) {
+ static const void *tbl[] = {&&L1};
+ (void)tbl;
+ return x;
+L1:
+ return 0;
+}
+
+// A's address comes from a constant table, B's from a runtime block-address
op;
+// both feed the same indirect branch.
+int m(int sel) {
+ static const void *ctbl[] = {&&A2};
+ void *p = &&B2;
+ void *t = (void *)ctbl[0];
+ void *dest = sel ? t : p;
+ goto *dest;
+A2:
+ return 1;
+B2:
+ return 2;
+}
+
+// CIR-DAG: cir.global "private" internal dso_local @f.tbl =
#cir.const_array<[#cir.block_addr_info<@f, "L1"> : !cir.ptr<!void>,
#cir.block_addr_info<@f, "L2"> : !cir.ptr<!void>]> : !cir.array<!cir.ptr<!void>
x 2>
+// CIR-DAG: cir.global "private" internal dso_local @g.tbl =
#cir.const_array<[#cir.block_addr_info<@g, "A"> : !cir.ptr<!void>,
#cir.block_addr_info<@g, "A"> : !cir.ptr<!void>, #cir.block_addr_info<@g, "B">
: !cir.ptr<!void>]> : !cir.array<!cir.ptr<!void> x 3>
+// CIR-DAG: cir.global "private" internal dso_local @h.tbl =
#cir.const_array<[#cir.block_addr_info<@h, "L1"> : !cir.ptr<!void>]> :
!cir.array<!cir.ptr<!void> x 1>
+// CIR-DAG: cir.global "private" internal dso_local @m.ctbl =
#cir.const_array<[#cir.block_addr_info<@m, "A2"> : !cir.ptr<!void>]> :
!cir.array<!cir.ptr<!void> x 1>
+
+// CIR: cir.func {{.*}} @f
+// CIR: %[[TBL:.*]] = cir.get_global @f.tbl
+// CIR: cir.indirect_br %{{.*}} : !cir.ptr<!void>, [
+// CIR-NEXT: ^[[L1BB:.*]],
+// CIR-NEXT: ^[[L2BB:.*]]
+// CIR: ]
+// CIR: ^[[L1BB]]:
+// CIR: cir.label "L1"
+// CIR: ^[[L2BB]]:
+// CIR: cir.label "L2"
+
+// CIR: cir.func {{.*}} @g
+// CIR: cir.indirect_br %{{.*}} : !cir.ptr<!void>, [
+// CIR-NEXT: ^[[ABB:.*]],
+// CIR-NEXT: ^[[ABB]],
+// CIR-NEXT: ^[[BBB:.*]]
+// CIR: ]
+// CIR: ^[[ABB]]:
+// CIR: cir.label "A"
+// CIR: ^[[BBB]]:
+// CIR: cir.label "B"
+
+// No indirect goto reaches the label, so the goto block is poisoned.
+// CIR: cir.func {{.*}} @h
+// CIR: cir.indirect_br %{{.*}} poison : !cir.ptr<!void>, [
+// CIR-NEXT: ^[[HL1:.*]]
+// CIR: ]
+// CIR: ^[[HL1]]:
+// CIR: cir.label "L1"
+
+// A2 comes from the constant table, B2 from a runtime block-address op; both
+// are successors of the one indirect branch.
+// CIR: cir.func {{.*}} @m
+// CIR: cir.block_address <@m, "B2">
+// CIR: cir.indirect_br
+// CIR-DAG: cir.label "A2"
+// CIR-DAG: cir.label "B2"
+
+// LLVM-DAG: @f.tbl = internal global [2 x ptr] [ptr blockaddress(@f,
%[[L1:[0-9]+]]), ptr blockaddress(@f, %[[L2:[0-9]+]])], align 16
+// LLVM-DAG: @g.tbl = internal global [3 x ptr] [ptr blockaddress(@g,
%[[GA:[0-9]+]]), ptr blockaddress(@g, %[[GA]]), ptr blockaddress(@g,
%[[GB:[0-9]+]])], align 16
+// LLVM-DAG: @h.tbl = internal global [1 x ptr] [ptr blockaddress(@h,
%{{[0-9]+}})], align 8
+// LLVM-DAG: @m.ctbl = internal global [1 x ptr] [ptr blockaddress(@m,
%{{[0-9]+}})], align 8
+
+// LLVM: define dso_local i32 @f(i32 noundef %{{.*}})
+// LLVM: indirectbr ptr %{{.*}}, [label %[[L1]], label %[[L2]]]
+
+// LLVM: define dso_local i32 @g(i32 noundef %{{.*}})
+// LLVM: indirectbr ptr %{{.*}}, [label %[[GA]], label %[[GA]], label
%[[GB]]]
+
+// LLVM: define dso_local i32 @h(i32 noundef %{{.*}})
+// LLVM: indirectbr ptr poison, [label %{{[0-9]+}}]
+
+// LLVM: define dso_local i32 @m(i32 noundef %{{.*}})
+// LLVM: indirectbr ptr %{{.*}}, [label %{{[0-9]+}}, label %{{[0-9]+}}]
+
+// OGCG-DAG: @f.tbl = internal global [2 x ptr] [ptr blockaddress(@f, %L1),
ptr blockaddress(@f, %L2)], align 16
+// OGCG-DAG: @g.tbl = internal global [3 x ptr] [ptr blockaddress(@g, %A), ptr
blockaddress(@g, %A), ptr blockaddress(@g, %B)], align 16
+// OGCG-DAG: @h.tbl = internal global [1 x ptr] [ptr blockaddress(@h, %L1)],
align 8
+// OGCG-DAG: @m.ctbl = internal global [1 x ptr] [ptr blockaddress(@m, %A2)],
align 8
+
+// OGCG: define dso_local i32 @f(i32 noundef %{{.*}})
----------------
adams381 wrote:
f/g/m share one `LLVM` prefix now. h can't: CIR emits no indirect branch there
while classic emits the poison one, so its branch check stays split
(LLVMCIR/OGCG).
https://github.com/llvm/llvm-project/pull/201644
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits