@@ -244,16 +244,29 @@ static void createDeclareAllocFuncWithArg(mlir::OpBuilder &modBuilder,
244244  if  (unwrapFirBox)
245245    asFortranDesc << accFirDescriptorPostfix.str ();
246246
247-   //  Use declare_enter for the descriptor so the runtime mirrors allocation
248-   //  semantics instead of issuing an update. This ensures the descriptor's
249-   //  device-side metadata is established via a structured begin.
250-   EntryOp descEntryOp = createDataEntryOp<EntryOp>(
251-       builder, loc, registerFuncOp.getArgument (0 ), asFortranDesc, bounds,
252-       /* structured=*/ false , /* implicit=*/ true , clause, descTy,
253-       /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
254-   mlir::acc::DeclareEnterOp::create (
255-       builder, loc, mlir::acc::DeclareTokenType::get (descEntryOp.getContext ()),
256-       mlir::ValueRange (descEntryOp.getAccVar ()));
247+   //  For descriptor, preserve old behavior when unwrapping FIR box: update.
248+   if  (unwrapFirBox) {
249+     mlir::acc::UpdateDeviceOp updateDeviceOp =
250+         createDataEntryOp<mlir::acc::UpdateDeviceOp>(
251+             builder, loc, registerFuncOp.getArgument (0 ), asFortranDesc, bounds,
252+             /* structured=*/ false , /* implicit=*/ true ,
253+             mlir::acc::DataClause::acc_update_device, descTy,
254+             /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
255+     llvm::SmallVector<int32_t > operandSegments{0 , 0 , 0 , 1 };
256+     llvm::SmallVector<mlir::Value> operands{updateDeviceOp.getResult ()};
257+     createSimpleOp<mlir::acc::UpdateOp>(builder, loc, operands,
258+                                         operandSegments);
259+   } else  {
260+     //  New behavior: start a structured region with declare_enter.
261+     EntryOp descEntryOp = createDataEntryOp<EntryOp>(
262+         builder, loc, registerFuncOp.getArgument (0 ), asFortranDesc, bounds,
263+         /* structured=*/ false , /* implicit=*/ true , clause, descTy,
264+         /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
265+     mlir::acc::DeclareEnterOp::create (
266+         builder, loc,
267+         mlir::acc::DeclareTokenType::get (descEntryOp.getContext ()),
268+         mlir::ValueRange (descEntryOp.getAccVar ()));
269+   }
257270
258271  if  (unwrapFirBox) {
259272    mlir::Value desc =
@@ -298,30 +311,58 @@ static void createDeclareDeallocFuncWithArg(
298311  }
299312
300313  llvm::SmallVector<mlir::Value> bounds;
301-   mlir::acc::GetDevicePtrOp entryOp =
302-       createDataEntryOp<mlir::acc::GetDevicePtrOp>(
303-           builder, loc, var, asFortran, bounds,
304-           /* structured=*/ false , /* implicit=*/ false , clause, var.getType (),
305-           /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
306-   mlir::acc::DeclareExitOp::create (builder, loc, mlir::Value{},
307-                                    mlir::ValueRange (entryOp.getAccVar ()));
308- 
309-   if  constexpr  (std::is_same_v<ExitOp, mlir::acc::CopyoutOp> ||
310-                 std::is_same_v<ExitOp, mlir::acc::UpdateHostOp>)
311-     ExitOp::create (builder, entryOp.getLoc (), entryOp.getAccVar (),
312-                    entryOp.getVar (), entryOp.getVarType (), entryOp.getBounds (),
313-                    entryOp.getAsyncOperands (),
314-                    entryOp.getAsyncOperandsDeviceTypeAttr (),
315-                    entryOp.getAsyncOnlyAttr (), entryOp.getDataClause (),
316-                    /* structured=*/ false , /* implicit=*/ false ,
317-                    builder.getStringAttr (*entryOp.getName ()));
318-   else 
319-     ExitOp::create (builder, entryOp.getLoc (), entryOp.getAccVar (),
320-                    entryOp.getBounds (), entryOp.getAsyncOperands (),
321-                    entryOp.getAsyncOperandsDeviceTypeAttr (),
322-                    entryOp.getAsyncOnlyAttr (), entryOp.getDataClause (),
323-                    /* structured=*/ false , /* implicit=*/ false ,
324-                    builder.getStringAttr (*entryOp.getName ()));
314+   if  (unwrapFirBox) {
315+     //  Unwrap: delete device payload using getdeviceptr + declare_exit + ExitOp
316+     mlir::acc::GetDevicePtrOp entryOp =
317+         createDataEntryOp<mlir::acc::GetDevicePtrOp>(
318+             builder, loc, var, asFortran, bounds,
319+             /* structured=*/ false , /* implicit=*/ false , clause, var.getType (),
320+             /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
321+     mlir::acc::DeclareExitOp::create (builder, loc, mlir::Value{},
322+                                      mlir::ValueRange (entryOp.getAccVar ()));
323+ 
324+     if  constexpr  (std::is_same_v<ExitOp, mlir::acc::CopyoutOp> ||
325+                   std::is_same_v<ExitOp, mlir::acc::UpdateHostOp>)
326+       ExitOp::create (builder, entryOp.getLoc (), entryOp.getAccVar (),
327+                      entryOp.getVar (), entryOp.getVarType (),
328+                      entryOp.getBounds (), entryOp.getAsyncOperands (),
329+                      entryOp.getAsyncOperandsDeviceTypeAttr (),
330+                      entryOp.getAsyncOnlyAttr (), entryOp.getDataClause (),
331+                      /* structured=*/ false , /* implicit=*/ false ,
332+                      builder.getStringAttr (*entryOp.getName ()));
333+     else 
334+       ExitOp::create (builder, entryOp.getLoc (), entryOp.getAccVar (),
335+                      entryOp.getBounds (), entryOp.getAsyncOperands (),
336+                      entryOp.getAsyncOperandsDeviceTypeAttr (),
337+                      entryOp.getAsyncOnlyAttr (), entryOp.getDataClause (),
338+                      /* structured=*/ false , /* implicit=*/ false ,
339+                      builder.getStringAttr (*entryOp.getName ()));
340+   } else  {
341+     mlir::acc::GetDevicePtrOp entryOp =
342+         createDataEntryOp<mlir::acc::GetDevicePtrOp>(
343+             builder, loc, var, asFortran, bounds,
344+             /* structured=*/ false , /* implicit=*/ false , clause, var.getType (),
345+             /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
346+     mlir::acc::DeclareExitOp::create (builder, loc, mlir::Value{},
347+                                      mlir::ValueRange (entryOp.getAccVar ()));
348+ 
349+     if  constexpr  (std::is_same_v<ExitOp, mlir::acc::CopyoutOp> ||
350+                   std::is_same_v<ExitOp, mlir::acc::UpdateHostOp>)
351+       ExitOp::create (builder, entryOp.getLoc (), entryOp.getAccVar (),
352+                      entryOp.getVar (), entryOp.getVarType (),
353+                      entryOp.getBounds (), entryOp.getAsyncOperands (),
354+                      entryOp.getAsyncOperandsDeviceTypeAttr (),
355+                      entryOp.getAsyncOnlyAttr (), entryOp.getDataClause (),
356+                      /* structured=*/ false , /* implicit=*/ false ,
357+                      builder.getStringAttr (*entryOp.getName ()));
358+     else 
359+       ExitOp::create (builder, entryOp.getLoc (), entryOp.getAccVar (),
360+                      entryOp.getBounds (), entryOp.getAsyncOperands (),
361+                      entryOp.getAsyncOperandsDeviceTypeAttr (),
362+                      entryOp.getAsyncOnlyAttr (), entryOp.getDataClause (),
363+                      /* structured=*/ false , /* implicit=*/ false ,
364+                      builder.getStringAttr (*entryOp.getName ()));
365+   }
325366
326367  //  Generate the post dealloc function.
327368  modBuilder.setInsertionPointAfter (preDeallocOp);
@@ -337,15 +378,28 @@ static void createDeclareDeallocFuncWithArg(
337378    asFortran << accFirDescriptorPostfix.str ();
338379  }
339380
340-   //  End the structured declare region for the descriptor or its payload
341-   //  using declare_exit instead of issuing an update.
342-   mlir::acc::GetDevicePtrOp postEntryOp =
343-       createDataEntryOp<mlir::acc::GetDevicePtrOp>(
344-           builder, loc, var, asFortran, bounds,
345-           /* structured=*/ false , /* implicit=*/ true , clause, var.getType (),
346-           /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
347-   mlir::acc::DeclareExitOp::create (builder, loc, mlir::Value{},
348-                                    mlir::ValueRange (postEntryOp.getAccVar ()));
381+   if  (unwrapFirBox) {
382+     //  Old behavior: update descriptor after deallocation.
383+     mlir::acc::UpdateDeviceOp updateDeviceOp =
384+         createDataEntryOp<mlir::acc::UpdateDeviceOp>(
385+             builder, loc, var, asFortran, bounds,
386+             /* structured=*/ false , /* implicit=*/ true ,
387+             mlir::acc::DataClause::acc_update_device, var.getType (),
388+             /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
389+     llvm::SmallVector<int32_t > operandSegments{0 , 0 , 0 , 1 };
390+     llvm::SmallVector<mlir::Value> operands{updateDeviceOp.getResult ()};
391+     createSimpleOp<mlir::acc::UpdateOp>(builder, loc, operands,
392+                                         operandSegments);
393+   } else  {
394+     //  New behavior: end structured region with declare_exit.
395+     mlir::acc::GetDevicePtrOp postEntryOp =
396+         createDataEntryOp<mlir::acc::GetDevicePtrOp>(
397+             builder, loc, var, asFortran, bounds,
398+             /* structured=*/ false , /* implicit=*/ true , clause, var.getType (),
399+             /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
400+     mlir::acc::DeclareExitOp::create (builder, loc, mlir::Value{},
401+                                      mlir::ValueRange (postEntryOp.getAccVar ()));
402+   }
349403  modBuilder.setInsertionPointAfter (postDeallocOp);
350404  builder.restoreInsertionPoint (crtInsPt);
351405}
@@ -3988,16 +4042,28 @@ static void createDeclareAllocFunc(mlir::OpBuilder &modBuilder,
39884042    asFortranDesc << accFirDescriptorPostfix.str ();
39894043  llvm::SmallVector<mlir::Value> bounds;
39904044
3991-   //  Use declare_enter for the descriptor so the runtime mirrors allocation
3992-   //  semantics instead of issuing an update. This ensures the descriptor's
3993-   //  device-side metadata is established via a structured begin.
3994-   EntryOp descEntryOp = createDataEntryOp<EntryOp>(
3995-       builder, loc, addrOp, asFortranDesc, bounds,
3996-       /* structured=*/ false , /* implicit=*/ true , clause, addrOp.getType (),
3997-       /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
3998-   mlir::acc::DeclareEnterOp::create (
3999-       builder, loc, mlir::acc::DeclareTokenType::get (descEntryOp.getContext ()),
4000-       mlir::ValueRange (descEntryOp.getAccVar ()));
4045+   //  For unwrapFirBox=false this remains declare_enter; for unwrapFirBox=true,
4046+   //  the descriptor post-alloc remains update behavior.
4047+   if  (unwrapFirBox) {
4048+     mlir::acc::UpdateDeviceOp updDesc =
4049+         createDataEntryOp<mlir::acc::UpdateDeviceOp>(
4050+             builder, loc, addrOp, asFortranDesc, bounds,
4051+             /* structured=*/ false , /* implicit=*/ true ,
4052+             mlir::acc::DataClause::acc_update_device, addrOp.getType (),
4053+             /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
4054+     llvm::SmallVector<int32_t > seg{0 , 0 , 0 , 1 };
4055+     llvm::SmallVector<mlir::Value> ops{updDesc.getResult ()};
4056+     createSimpleOp<mlir::acc::UpdateOp>(builder, loc, ops, seg);
4057+   } else  {
4058+     EntryOp descEntryOp = createDataEntryOp<EntryOp>(
4059+         builder, loc, addrOp, asFortranDesc, bounds,
4060+         /* structured=*/ false , /* implicit=*/ true , clause, addrOp.getType (),
4061+         /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
4062+     mlir::acc::DeclareEnterOp::create (
4063+         builder, loc,
4064+         mlir::acc::DeclareTokenType::get (descEntryOp.getContext ()),
4065+         mlir::ValueRange (descEntryOp.getAccVar ()));
4066+   }
40014067
40024068  if  (unwrapFirBox) {
40034069    auto  loadOp = fir::LoadOp::create (builder, loc, addrOp.getResult ());
@@ -4090,15 +4156,27 @@ static void createDeclareDeallocFunc(mlir::OpBuilder &modBuilder,
40904156  if  (unwrapFirBox)
40914157    asFortran << accFirDescriptorPostfix.str ();
40924158  llvm::SmallVector<mlir::Value> bounds;
4093-   //  Use declare_exit for the descriptor to end the structured declare region
4094-   //  instead of issuing an update.
4095-   mlir::acc::GetDevicePtrOp descEntryOp =
4096-       createDataEntryOp<mlir::acc::GetDevicePtrOp>(
4097-           builder, loc, addrOp, asFortran, bounds,
4098-           /* structured=*/ false , /* implicit=*/ true , clause, addrOp.getType (),
4099-           /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
4100-   mlir::acc::DeclareExitOp::create (builder, loc, mlir::Value{},
4101-                                    mlir::ValueRange (descEntryOp.getAccVar ()));
4159+   if  (unwrapFirBox) {
4160+     //  Unwrap mode: update the descriptor after deallocation (no declare_exit).
4161+     mlir::acc::UpdateDeviceOp updDesc =
4162+         createDataEntryOp<mlir::acc::UpdateDeviceOp>(
4163+             builder, loc, addrOp, asFortran, bounds,
4164+             /* structured=*/ false , /* implicit=*/ true ,
4165+             mlir::acc::DataClause::acc_update_device, addrOp.getType (),
4166+             /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
4167+     llvm::SmallVector<int32_t > seg{0 , 0 , 0 , 1 };
4168+     llvm::SmallVector<mlir::Value> ops{updDesc.getResult ()};
4169+     createSimpleOp<mlir::acc::UpdateOp>(builder, loc, ops, seg);
4170+   } else  {
4171+     //  Default: end the structured declare region using declare_exit.
4172+     mlir::acc::GetDevicePtrOp descEntryOp =
4173+         createDataEntryOp<mlir::acc::GetDevicePtrOp>(
4174+             builder, loc, addrOp, asFortran, bounds,
4175+             /* structured=*/ false , /* implicit=*/ true , clause, addrOp.getType (),
4176+             /* async=*/  {}, /* asyncDeviceTypes=*/  {}, /* asyncOnlyDeviceTypes=*/  {});
4177+     mlir::acc::DeclareExitOp::create (builder, loc, mlir::Value{},
4178+                                      mlir::ValueRange (descEntryOp.getAccVar ()));
4179+   }
41024180  modBuilder.setInsertionPointAfter (postDeallocOp);
41034181}
41044182
0 commit comments