-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[flang][debug] Generate DISubprogramAttr for omp::TargetOp. #146532
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s | ||
// RUN: fir-opt --add-debug-info="debug-level=LineTablesOnly" --mlir-print-debuginfo %s | FileCheck %s --check-prefix=LINETABLE | ||
|
||
module attributes {dlti.dl_spec = #dlti.dl_spec<>} { | ||
func.func @_QQmain() attributes {fir.bindc_name = "test"} { | ||
%c13_i32 = arith.constant 13 : i32 | ||
%c12_i32 = arith.constant 12 : i32 | ||
%c6_i32 = arith.constant 6 : i32 | ||
%c1_i32 = arith.constant 1 : i32 | ||
%c5_i32 = arith.constant 5 : i32 | ||
%0 = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"} loc(#loc1) | ||
%1 = fircg.ext_declare %0 {uniq_name = "_QFEx"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc1) | ||
%2 = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFEy"} loc(#loc2) | ||
%3 = fircg.ext_declare %2 {uniq_name = "_QFEy"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc2) | ||
%4 = omp.map.info var_ptr(%1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "x"} | ||
%5 = omp.map.info var_ptr(%3 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "y"} | ||
omp.target map_entries(%4 -> %arg0, %5 -> %arg1 : !fir.ref<i32>, !fir.ref<i32>) { | ||
%16 = fircg.ext_declare %arg0 {uniq_name = "_QFEx"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc3) | ||
%17 = fircg.ext_declare %arg1 {uniq_name = "_QFEy"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc4) | ||
omp.terminator | ||
} loc(#loc5) | ||
return | ||
} | ||
} | ||
#loc1 = loc("test.f90":1:1) | ||
#loc2 = loc("test.f90":3:1) | ||
#loc3 = loc("test.f90":7:1) | ||
#loc4 = loc("test.f90":8:1) | ||
#loc5 = loc("test.f90":6:1) | ||
|
||
// CHECK: #[[SP:.*]] = #llvm.di_subprogram<{{.*}}name = "test"{{.*}}> | ||
// CHECK: #[[SP1:.*]] = #llvm.di_subprogram<{{.*}}name = "__omp_offloading_{{.*}}_QQmain_l6"{{.*}}line = 6{{.*}}subprogramFlags = "LocalToUnit|Definition"{{.*}}> | ||
// CHECK: #llvm.di_local_variable<scope = #[[SP]], name = "x"{{.*}}line = 1, type = #[[TY:.*]]> | ||
// CHECK: #llvm.di_local_variable<scope = #[[SP]], name = "y"{{.*}}line = 3, type = #[[TY]]> | ||
// CHECK: #llvm.di_local_variable<scope = #[[SP1]], name = "x"{{.*}}line = 7, type = #[[TY]]> | ||
// CHECK: #llvm.di_local_variable<scope = #[[SP1]], name = "y"{{.*}}line = 8, type = #[[TY]]> | ||
|
||
// LINETABLE: #[[SP:.*]] = #llvm.di_subprogram<{{.*}}name = "test"{{.*}}> | ||
// LINETABLE: #[[SP1:.*]] = #llvm.di_subprogram<{{.*}}name = "__omp_offloading_{{.*}}_QQmain_l6"{{.*}}line = 6{{.*}}subprogramFlags = "LocalToUnit|Definition"{{.*}}> | ||
// LINETABLE-NOT: #llvm.di_local_variable |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s | ||
|
||
module attributes {dlti.dl_spec = #dlti.dl_spec<>} { | ||
func.func @fn_(%arg0: !fir.ref<!fir.array<?x?xi32>> {fir.bindc_name = "b"}, %arg1: !fir.ref<i32> {fir.bindc_name = "c"}, %arg2: !fir.ref<i32> {fir.bindc_name = "d"}) { | ||
%c1 = arith.constant 1 : index | ||
%c0 = arith.constant 0 : index | ||
%0 = fir.alloca i32 | ||
%1 = fir.alloca i32 | ||
%2 = fir.undefined !fir.dscope | ||
%3 = fircg.ext_declare %arg1 dummy_scope %2 {uniq_name = "_QFfnEc"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc2) | ||
%4 = fircg.ext_declare %arg2 dummy_scope %2 {uniq_name = "_QFfnEd"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3) | ||
%5 = fir.load %3 : !fir.ref<i32> | ||
%6 = fir.convert %5 : (i32) -> index | ||
%9 = fir.load %4 : !fir.ref<i32> | ||
%10 = fir.convert %9 : (i32) -> index | ||
%15 = fircg.ext_declare %arg0(%6, %10) dummy_scope %2 {uniq_name = "_QFfnEb"} : (!fir.ref<!fir.array<?x?xi32>>, index, index, !fir.dscope) -> !fir.ref<!fir.array<?x?xi32>> loc(#loc4) | ||
%16 = fircg.ext_embox %15(%6, %10) : (!fir.ref<!fir.array<?x?xi32>>, index, index) -> !fir.box<!fir.array<?x?xi32>> | ||
%17:3 = fir.box_dims %16, %c0 : (!fir.box<!fir.array<?x?xi32>>, index) -> (index, index, index) | ||
%18 = arith.subi %17#1, %c1 : index | ||
%19 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%18 : index) extent(%17#1 : index) stride(%17#2 : index) start_idx(%c1 : index) {stride_in_bytes = true} | ||
%20 = arith.muli %17#2, %17#1 : index | ||
%21:3 = fir.box_dims %16, %c1 : (!fir.box<!fir.array<?x?xi32>>, index) -> (index, index, index) | ||
%22 = arith.subi %21#1, %c1 : index | ||
%23 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%22 : index) extent(%21#1 : index) stride(%20 : index) start_idx(%c1 : index) {stride_in_bytes = true} | ||
%24 = omp.map.info var_ptr(%15 : !fir.ref<!fir.array<?x?xi32>>, i32) map_clauses(tofrom) capture(ByRef) bounds(%19, %23) -> !fir.ref<!fir.array<?x?xi32>> {name = "b"} | ||
%25 = omp.map.info var_ptr(%1 : !fir.ref<i32>, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref<i32> {name = ""} | ||
%26 = omp.map.info var_ptr(%0 : !fir.ref<i32>, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref<i32> {name = ""} | ||
omp.target map_entries(%24 -> %arg3, %25 -> %arg4, %26 -> %arg5 : !fir.ref<!fir.array<?x?xi32>>, !fir.ref<i32>, !fir.ref<i32>) { | ||
%27 = fir.load %arg5 : !fir.ref<i32> | ||
%28 = fir.load %arg4 : !fir.ref<i32> | ||
%29 = fir.convert %27 : (i32) -> index | ||
%31 = fir.convert %28 : (i32) -> index | ||
%37 = fircg.ext_declare %arg3(%29, %31) {uniq_name = "_QFfnEb"} : (!fir.ref<!fir.array<?x?xi32>>, index, index) -> !fir.ref<!fir.array<?x?xi32>> loc(#loc5) | ||
omp.terminator | ||
} loc(#loc6) | ||
return | ||
} loc(#loc7) | ||
} | ||
#loc1 = loc("test.f90":1:1) | ||
#loc2 = loc("test.f90":3:1) | ||
#loc3 = loc("test.f90":7:1) | ||
#loc4 = loc("test.f90":8:1) | ||
#loc5 = loc("test.f90":6:1) | ||
#loc6 = loc("test.f90":16:1) | ||
#loc7 = loc("test.f90":26:1) | ||
|
||
|
||
// Test that variable size arrays inside target regions get their own | ||
// compiler generated variables for size. | ||
|
||
// CHECK: #[[SP:.*]] = #llvm.di_subprogram<{{.*}}name = "__omp_offloading_{{.*}}_fn__l16"{{.*}}> | ||
// CHECK: #llvm.di_local_variable<scope = #[[SP]], name = "._QFfnEb1"{{.*}}> | ||
// CHECK: #llvm.di_local_variable<scope = #[[SP]], name = "._QFfnEb2"{{.*}}> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5324,9 +5324,27 @@ static LogicalResult | |
convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder, | ||
LLVM::ModuleTranslation &moduleTranslation) { | ||
auto targetOp = cast<omp::TargetOp>(opInst); | ||
// The current debug location already has the DISubprogram for the outlined | ||
// function that will be created for the target op. We save it here so that | ||
// we can set it on the outlined function. | ||
llvm::DebugLoc outlinedFnLoc = builder.getCurrentDebugLocation(); | ||
if (failed(checkImplementationStatus(opInst))) | ||
return failure(); | ||
|
||
// During the handling of target op, we will generate instructions in the | ||
// parent function like call to the oulined function or branch to a new | ||
// BasicBlock. We set the debug location here to parent function so that those | ||
// get the correct debug locations. For outlined functions, the normal MLIR op | ||
// conversion will automatically pick the correct location. | ||
llvm::BasicBlock *parentBB = builder.GetInsertBlock(); | ||
assert(parentBB && "No insert block is set for the builder"); | ||
llvm::Function *parentLLVMFn = parentBB->getParent(); | ||
assert(parentLLVMFn && "Parent Function must be valid"); | ||
if (llvm::DISubprogram *SP = parentLLVMFn->getSubprogram()) | ||
builder.SetCurrentDebugLocation(llvm::DILocation::get( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After switching the debug location to the parent function for host-side calls, you should restore the original Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The callback which generates the body of the outlined function uses the correct location. |
||
parentLLVMFn->getContext(), outlinedFnLoc.getLine(), | ||
outlinedFnLoc.getCol(), SP, outlinedFnLoc.getInlinedAt())); | ||
|
||
llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); | ||
bool isTargetDevice = ompBuilder->Config.isTargetDevice(); | ||
bool isGPU = ompBuilder->Config.isGPU(); | ||
|
@@ -5420,6 +5438,9 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder, | |
assert(llvmParentFn && llvmOutlinedFn && | ||
"Both parent and outlined functions must exist at this point"); | ||
|
||
if (outlinedFnLoc && llvmParentFn->getSubprogram()) | ||
llvmOutlinedFn->setSubprogram(outlinedFnLoc->getScope()->getSubprogram()); | ||
|
||
if (auto attr = llvmParentFn->getFnAttribute("target-cpu"); | ||
attr.isStringAttribute()) | ||
llvmOutlinedFn->addFnAttr(attr); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s | ||
|
||
module attributes {omp.is_target_device = false} { | ||
llvm.func @test() { | ||
omp.target { | ||
omp.terminator | ||
} loc(#loc4) | ||
llvm.return | ||
} loc(#loc3) | ||
} | ||
#file = #llvm.di_file<"target.f90" in ""> | ||
#cu = #llvm.di_compile_unit<id = distinct[0]<>, | ||
sourceLanguage = DW_LANG_Fortran95, file = #file, isOptimized = false, | ||
emissionKind = Full> | ||
#sp_ty = #llvm.di_subroutine_type<callingConvention = DW_CC_normal> | ||
#sp = #llvm.di_subprogram<id = distinct[1]<>, compileUnit = #cu, scope = #file, | ||
name = "_QQmain", file = #file, subprogramFlags = "Definition", type = #sp_ty> | ||
#sp1 = #llvm.di_subprogram<id = distinct[2]<>, compileUnit = #cu, scope = #file, | ||
name = "__omp_offloading_target", file = #file, subprogramFlags = "Definition", | ||
type = #sp_ty> | ||
#loc1 = loc("target.f90":1:1) | ||
#loc2 = loc("target.f90":46:3) | ||
#loc3 = loc(fused<#sp>[#loc1]) | ||
#loc4 = loc(fused<#sp1>[#loc2]) | ||
|
||
// CHECK: ![[SP:.*]] = {{.*}}!DISubprogram(name: "__omp_offloading_target"{{.*}}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new local-variable fixup is still using the old scope (
OldVar->getScope()
) instead of the outlined function's DISubprogram scope. You should clone or otherwise obtain a scope rooted at the new SP and pass that toDILocalVariable::get
, as in the originalcloneScopeForSubprogram
approach.Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using
OldVar->getScope()
is the right thing here.