llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.12k stars 11.61k forks source link

[Clang] ICE when OpenMP declare mapper generates debug info #105828

Open mikaoP opened 1 month ago

mikaoP commented 1 month ago
typedef struct {
  int a;
} C;
#pragma omp declare mapper(C s) map(to : s.a)

typedef struct {
  C f;
} D;

int main() {
  D sa[10];
#pragma omp target map(tofrom : sa[0 : 2])
  {

  }
}

This simple test is based on declare_mapper_nested_default_mappers_1.cpp Command: clang -fopenmp t1.cpp -fopenmp-targets=x86_64-unknown-linux-gnu -g

inlinable function call in a function with debug info must have a !dbg location
  call void @.omp_mapper._ZTS1C.default(ptr %7, ptr %omp.arraymap.ptrcurrent, ptr %f, i64 4, i64 %omp.maptype, ptr @1) #3

Without -g it works as is the way offload tests are run

llvmbot commented 1 month ago

@llvm/issue-subscribers-debuginfo

Author: None (mikaoP)

```cpp typedef struct { int a; } C; #pragma omp declare mapper(C s) map(to : s.a) typedef struct { C f; } D; int main() { D sa[10]; #pragma omp target map(tofrom : sa[0 : 2]) { } } ``` This simple test is based on `declare_mapper_nested_default_mappers_1.cpp` Command: `clang -fopenmp t1.cpp -fopenmp-targets=x86_64-unknown-linux-gnu -g` ``` inlinable function call in a function with debug info must have a !dbg location call void @.omp_mapper._ZTS1C.default(ptr %7, ptr %omp.arraymap.ptrcurrent, ptr %f, i64 4, i64 %omp.maptype, ptr @1) #3 ``` Without `-g` it works as is the way offload tests are run
jmorse commented 3 weeks ago

I've re-titled to indicate that there's a crash / in-compiler-exception when this happens -- that's substantially more significant than just not producing debugging information.

I took a look at the generated code, and I'm not familiar with OpenMP at all. However, there are a few function calls being generated that don't have !dbg / DILocations attached. In modules and functions with debug-info, if a function can potentially be inlined, the call-site must have a !dbg / DILocation attached to ensure an inlining-chain can be produced.

Here's the code in the relevant function, in case it helps with further analysis:

; Function Attrs: noinline nounwind uwtable
define internal void @.omp_mapper._ZTS1D.default(ptr noundef %0, ptr noundef %1, ptr noundef %2, i64 noundef %3, i64 noundef %4, ptr noundef %5) #2 !dbg !40 {
entry:
  %.addr = alloca ptr, align 8
  %.addr1 = alloca ptr, align 8
  %.addr2 = alloca ptr, align 8
  %.addr3 = alloca i64, align 8
  %.addr4 = alloca i64, align 8
  %.addr5 = alloca ptr, align 8
  store ptr %0, ptr %.addr, align 8
    #dbg_declare(ptr %.addr, !42, !DIExpression(), !44)
  store ptr %1, ptr %.addr1, align 8
    #dbg_declare(ptr %.addr1, !45, !DIExpression(), !44)
  store ptr %2, ptr %.addr2, align 8
    #dbg_declare(ptr %.addr2, !46, !DIExpression(), !44)
  store i64 %3, ptr %.addr3, align 8
    #dbg_declare(ptr %.addr3, !47, !DIExpression(), !44)
  store i64 %4, ptr %.addr4, align 8
    #dbg_declare(ptr %.addr4, !49, !DIExpression(), !44)
  store ptr %5, ptr %.addr5, align 8
    #dbg_declare(ptr %.addr5, !50, !DIExpression(), !44)
  %6 = load i64, ptr %.addr3, align 8
  %7 = load ptr, ptr %.addr, align 8
  %8 = load ptr, ptr %.addr1, align 8
  %9 = load ptr, ptr %.addr2, align 8
  %10 = udiv exact i64 %6, 4
  %11 = getelementptr %struct.D, ptr %9, i64 %10
  %12 = load i64, ptr %.addr4, align 8
  %13 = load ptr, ptr %.addr5, align 8
  %omp.arrayinit.isarray = icmp sgt i64 %10, 1
  %14 = and i64 %12, 8
  %15 = icmp ne ptr %8, %9
  %16 = and i64 %12, 16
  %17 = icmp ne i64 %16, 0
  %18 = and i1 %15, %17
  %19 = or i1 %omp.arrayinit.isarray, %18
  %.omp.array..init..delete = icmp eq i64 %14, 0
  %20 = and i1 %19, %.omp.array..init..delete
  br i1 %20, label %.omp.array..init, label %omp.arraymap.head

.omp.array..init:                                 ; preds = %entry
  %21 = mul nuw i64 %10, 4
  %22 = and i64 %12, -4
  %23 = or i64 %22, 512
  call void @__tgt_push_mapper_component(ptr %7, ptr %8, ptr %9, i64 %21, i64 %23, ptr %13)
  br label %omp.arraymap.head

omp.arraymap.head:                                ; preds = %.omp.array..init, %entry
  %omp.arraymap.isempty = icmp eq ptr %9, %11
  br i1 %omp.arraymap.isempty, label %omp.done, label %omp.arraymap.body

omp.arraymap.body:                                ; preds = %omp.type.end, %omp.arraymap.head
  %omp.arraymap.ptrcurrent = phi ptr [ %9, %omp.arraymap.head ], [ %omp.arraymap.next, %omp.type.end ]
  %f = getelementptr inbounds %struct.D, ptr %omp.arraymap.ptrcurrent, i32 0, i32 0, !dbg !51
  %24 = call i64 @__tgt_mapper_num_components(ptr %7)
  %25 = shl i64 %24, 48
  %26 = add nuw i64 515, %25
  %27 = and i64 %12, 3
  %28 = icmp eq i64 %27, 0
  br i1 %28, label %omp.type.alloc, label %omp.type.alloc.else

omp.type.alloc:                                   ; preds = %omp.arraymap.body
  %29 = and i64 %26, -4
  br label %omp.type.end

omp.type.alloc.else:                              ; preds = %omp.arraymap.body
  %30 = icmp eq i64 %27, 1
  br i1 %30, label %omp.type.to, label %omp.type.to.else

omp.type.to:                                      ; preds = %omp.type.alloc.else
  %31 = and i64 %26, -3
  br label %omp.type.end

omp.type.to.else:                                 ; preds = %omp.type.alloc.else
  %32 = icmp eq i64 %27, 2
  br i1 %32, label %omp.type.from, label %omp.type.end

omp.type.from:                                    ; preds = %omp.type.to.else
  %33 = and i64 %26, -2
  br label %omp.type.end

omp.type.end:                                     ; preds = %omp.type.from, %omp.type.to.else, %omp.type.to, %omp.type.alloc
  %omp.maptype = phi i64 [ %29, %omp.type.alloc ], [ %31, %omp.type.to ], [ %33, %omp.type.from ], [ %26, %omp.type.to.else ]
  call void @.omp_mapper._ZTS1C.default(ptr %7, ptr %omp.arraymap.ptrcurrent, ptr %f, i64 4, i64 %omp.maptype, ptr @1) #3
  %omp.arraymap.next = getelementptr %struct.D, ptr %omp.arraymap.ptrcurrent, i32 1
  %omp.arraymap.isdone = icmp eq ptr %omp.arraymap.next, %11
  br i1 %omp.arraymap.isdone, label %omp.arraymap.exit, label %omp.arraymap.body

omp.arraymap.exit:                                ; preds = %omp.type.end
  %omp.arrayinit.isarray6 = icmp sgt i64 %10, 1
  %34 = and i64 %12, 8
  %.omp.array..del..delete = icmp ne i64 %34, 0
  %35 = and i1 %omp.arrayinit.isarray6, %.omp.array..del..delete
  br i1 %35, label %.omp.array..del, label %omp.done

.omp.array..del:                                  ; preds = %omp.arraymap.exit
  %36 = mul nuw i64 %10, 4
  %37 = and i64 %12, -4
  %38 = or i64 %37, 512
  call void @__tgt_push_mapper_component(ptr %7, ptr %8, ptr %9, i64 %36, i64 %38, ptr %13)
  br label %omp.done

omp.done:                                         ; preds = %.omp.array..del, %omp.arraymap.exit, %omp.arraymap.head
  ret void, !dbg !52
}
jmorse commented 3 weeks ago

(Well, verifier-error from code that clang has only just generated is basically a crash / ICE, users certainly don't have a useful workaround).