blob: 55e87ad217fc1dc99345317bb16531df35f01580 [file] [edit]
// RUN: %eopt --enzyme %s | FileCheck %s
// A comdat says which of the identical copies of a symbol the linker should
// keep, and it keeps or discards the whole group at once. The derivative is
// cloned from the primal and so arrived holding the primal's comdat, which put
// it in that group -- but only the translation units that differentiate the
// primal put a derivative in it. A unit that merely calls the primal offers a
// group of one under the same key, and if that is the copy the linker keeps,
// the derivative goes with the copy it discarded:
//
// undefined reference to `fwddiffe_ZNK4mfem6future14tensor_ndarray...'
//
// even though the object that made the call also defined the symbol. Five of
// MFEM's unit-test objects offered the derivative-less group for the same key
// (EnzymeAD/Enzyme-JAX#2778).
module {
llvm.comdat @__llvm_global_comdat {
llvm.comdat_selector @f any
}
llvm.func @f(%p: !llvm.ptr) comdat(@__llvm_global_comdat::@f) {
%v = llvm.load %p : !llvm.ptr -> f64
%s = arith.mulf %v, %v : f64
llvm.store %s, %p : f64, !llvm.ptr
llvm.return
}
func.func @df(%p: !llvm.ptr, %dp: !llvm.ptr) {
enzyme.fwddiff @f(%p, %dp) { activity=[#enzyme<activity enzyme_dup>], ret_activity=[] } : (!llvm.ptr, !llvm.ptr) -> ()
return
}
}
// The derivative gets a group of its own, keyed on its own name, so it still
// dedupes against the other units that built the same derivative and nothing
// else can take it away. The kind of deduplication is the primal's.
// CHECK: llvm.comdat @__llvm_global_comdat {
// CHECK-DAG: llvm.comdat_selector @f any
// CHECK-DAG: llvm.comdat_selector @fwddiffef any
// CHECK: }
// CHECK: llvm.func @f(%{{.+}}: !llvm.ptr) comdat(@__llvm_global_comdat::@f)
// CHECK: llvm.func @fwddiffef(%{{.+}}: !llvm.ptr, %{{.+}}: !llvm.ptr) comdat(@__llvm_global_comdat::@fwddiffef)