// RUN: %clang_cc1 -triple aarch64-linux-android29 -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s // RUN: %clang_cc1 -triple aarch64-linux-android29 -fclangir -emit-llvm %s -o %t-cir.ll // RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s // RUN: %clang_cc1 -triple aarch64-linux-android29 -emit-llvm %s -o %t.ll // RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s // Verify that __attribute__((annotate(...))) is properly handled in CIR. // The annotations are preserved as cir.annotation attributes on globals and // functions. This is used by the Android NDK (__INTRODUCED_IN macro). // // LLVM lowering emits @llvm.global.annotations matching OGCG (with one // entry per annotation per annotated value). String constants and per-arg // structs are deduplicated by content / ArrayAttr identity respectively, // so two functions with identical args share an .args global. // Globals are emitted before functions in CIR, so check them first. __attribute__((annotate("introduced_in=29"))) int annotated_var = 42; // All globals (including static locals) are emitted before functions in CIR; // check them all together up here so subsequent function CHECKs can rely on // strict-order matching for the function section. // CIR-DAG: cir.global external @annotated_var = #cir.int<42> : !s32i [#cir.annotation<"introduced_in=29">] // CIR-DAG: cir.global "private" internal{{.*}} @{{.*counter.*}} = #cir.int<0> : !s32i [#cir.annotation<"static_local">] // LLVM-DAG: @annotated_var = global i32 42 // LLVM-DAG: @{{.*counter.*}} = internal{{.*}} global i32 0 // OGCG-DAG: @annotated_var = global i32 42 // OGCG-DAG: @{{.*counter.*}} = internal{{.*}} global i32 0 // OGCG-DAG: @llvm.global.annotations = appending global // CIR-side LLVM lowering also emits @llvm.global.annotations and the // supporting strings/args constants. The CHECKs below cover each branch // of the lowering helpers (string cache hit + miss, isArg=true vs false, // args cache hit + miss, named-with-index vs named-without-index). // // (a) The first-emitted annotation-name string uses the no-index name // "@.str.annotation" (cache.empty() branch). It happens to hold // "static_local" given collection order (globals first), so we pin // both the name and the content here. // LLVM-DAG: @.str.annotation = private unnamed_addr constant {{.*}} c"static_local\00", section "llvm.metadata" // // (b) Subsequent name strings get a numeric index (cache.size() branch). // The second-emitted string is the source-file path, shared by every // annotation entry below (string cache HIT path). // LLVM-DAG: @.str.1.annotation = private unnamed_addr constant {{.*}} c"{{.*annotate-attribute\.c}}\00", section "llvm.metadata" // // (c) Every other annotation name we wrote survives as its own // llvm.metadata string. Each line targets a distinct emitted // constant (static_local is covered above by (a)). // LLVM-DAG: constant {{.*}} c"introduced_in=29\00", section "llvm.metadata" // LLVM-DAG: constant {{.*}} c"test_annotation\00", section "llvm.metadata" // LLVM-DAG: constant {{.*}} c"api_level=29\00", section "llvm.metadata" // LLVM-DAG: constant {{.*}} c"ann1\00", section "llvm.metadata" // LLVM-DAG: constant {{.*}} c"ann2\00", section "llvm.metadata" // LLVM-DAG: constant {{.*}} c"with_args\00", section "llvm.metadata" // LLVM-DAG: constant {{.*}} c"uniq\00", section "llvm.metadata" // LLVM-DAG: constant {{.*}} c"inherited_decl_ann\00", section "llvm.metadata" // LLVM-DAG: constant {{.*}} c"inherited_def_ann\00", section "llvm.metadata" // // (d) String args take the isArg=true branch of // getOrCreateAnnotationStringGlobal: ".annotation.arg" suffix, // alignment 1, and NO llvm.metadata section. Both the no-index and // numbered name forms are present. // LLVM-DAG: @.str.annotation.arg = private unnamed_addr constant [{{[0-9]+}} x i8] c"str_arg\00", align 1 // LLVM-DAG: @.str.1.annotation.arg = private unnamed_addr constant [{{[0-9]+}} x i8] c"shared\00", align 1 // // (e) Args struct globals follow @.args{,.}.annotation: first one // uses the no-index branch (argsCache.empty()), subsequent ones // get a numeric suffix. Both branches are exercised here. // LLVM-DAG: @.args.annotation = private unnamed_addr constant { ptr, i32 } { ptr @.str{{(\.[0-9]+)?}}.annotation.arg, i32 42 }, section "llvm.metadata" // LLVM-DAG: @.args.1.annotation = private unnamed_addr constant { ptr, i32 } { ptr @.str{{(\.[0-9]+)?}}.annotation.arg, i32 7 }, section "llvm.metadata" // // (f) The @llvm.global.annotations array is appending and lives in // llvm.metadata. uniq_a and uniq_b reference the SAME args global // (@.args.1.annotation) — the args-cache HIT path. // LLVM-DAG: @llvm.global.annotations = appending global [11 x { ptr, ptr, ptr, i32, ptr }] [{{.*}} { ptr @uniq_a, ptr {{[^,]+}}, ptr {{[^,]+}}, i32 {{[0-9]+}}, ptr @.args.1.annotation }, {{.*}} { ptr @uniq_b, ptr {{[^,]+}}, ptr {{[^,]+}}, i32 {{[0-9]+}}, ptr @.args.1.annotation }{{.*}}], section "llvm.metadata" __attribute__((annotate("test_annotation"))) void annotated_func(void) {} // CIR: cir.func {{.*}} @annotated_func() [#cir.annotation<"test_annotation">] // LLVM: define{{.*}} void @annotated_func() // OGCG: define{{.*}} void @annotated_func() // Test: annotated function declaration used before definition exercises the // deferred annotation path in emitGlobal. __attribute__((annotate("api_level=29"))) void deferred_annotated(void); void caller(void) { deferred_annotated(); } __attribute__((annotate("api_level=29"))) void deferred_annotated(void) {} // CIR: cir.func {{.*}} @deferred_annotated() [#cir.annotation<"api_level=29">] // LLVM: define{{.*}} void @deferred_annotated() // OGCG: define{{.*}} void @deferred_annotated() // Test: multiple annotations on a single function. __attribute__((annotate("ann1"))) __attribute__((annotate("ann2"))) void multi_annotated(void) {} // CIR: cir.func {{.*}} @multi_annotated() [#cir.annotation<"ann1">, #cir.annotation<"ann2">] // LLVM: define{{.*}} void @multi_annotated() // OGCG: define{{.*}} void @multi_annotated() // Test: annotation with arguments. __attribute__((annotate("with_args", "str_arg", 42))) void annotated_with_args(void) {} // CIR: cir.func {{.*}} @annotated_with_args() [#cir.annotation<"with_args", ["str_arg", 42 : i32]>] // LLVM: define{{.*}} void @annotated_with_args() // OGCG: define{{.*}} void @annotated_with_args() // Test: function-local static variable with annotation. Exercises the // emitStaticVarDecl -> addGlobalAnnotations path (distinct from // emitGlobalVarDefinition for plain globals). The CIR-DAG / LLVM-DAG // CHECKs for the emitted global live in the globals block at the top. void with_static_annotated(void) { static int counter __attribute__((annotate("static_local"))) = 0; counter++; } // Test: argument-uniquing path in emitAnnotationArgs. Two annotations with // identical arg lists should share the same args ArrayAttr (the FoldingSet // cache hit). MLIR uniques attributes on identity, so identical printed // output here is the observable signal that uniquing took effect. __attribute__((annotate("uniq", "shared", 7))) void uniq_a(void) {} __attribute__((annotate("uniq", "shared", 7))) void uniq_b(void) {} // CIR: cir.func {{.*}} @uniq_a() [#cir.annotation<"uniq", ["shared", 7 : i32]>] // CIR: cir.func {{.*}} @uniq_b() [#cir.annotation<"uniq", ["shared", 7 : i32]>] // OGCG: define{{.*}} void @uniq_a() // OGCG: define{{.*}} void @uniq_b() // Test: declaration annotated, then defined annotated, with a forward use // in between. This exercises the emitGlobal "update deferred annotations // with the latest declaration" path: the call site triggers // getOrCreateCIRFunction (records the decl), then the definition's // emitGlobal sees the existing GlobalValue and updates the deferred map // with the *defining* decl so all inherited annotations stick. __attribute__((annotate("inherited_decl_ann"))) void inherited(void); void inherited_caller(void) { inherited(); } __attribute__((annotate("inherited_def_ann"))) void inherited(void) {} // Both annotations should appear (decl + def). // CIR: cir.func {{.*}} @inherited() [#cir.annotation<"inherited_decl_ann">, #cir.annotation<"inherited_def_ann">] // OGCG: define{{.*}} void @inherited()