================
@@ -3595,6 +3595,75 @@ static bool
canEmitSpuriousReferenceToVariable(CodeGenFunction &CGF,
}
}
+/// Emit an LValue for a structured binding captured in an OpenMP region.
+/// Handles extracting individual bindings from the captured decomposed
+/// declaration (struct fields, array elements, etc.).
+LValue CodeGenFunction::EmitOMPCapturedBindingLValue(const BindingDecl *BD) {
+ assert(CapturedStmtInfo && "Expected to be inside a captured region");
+ assert(CapturedStmtInfo->getKind() == CapturedRegionKind::CR_OpenMP &&
+ "Expected OpenMP captured region");
+ assert(CGM.getLangOpts().OpenMP && "Expected OpenMP to be enabled");
+
+ if (auto It = LocalDeclMap.find(BD->getCanonicalDecl());
+ It != LocalDeclMap.end())
+ return MakeAddrLValue(It->second, BD->getType());
+
+ const auto *DD = cast<VarDecl>(BD->getDecomposedDecl());
+
+ // Check if the original variable (what DD decomposes) has been mapped.
+ // If so, use the original variable instead of DD to avoid capturing DD.
+ const VarDecl *TargetDecl = DD;
+ if (const auto *DecompDecl = dyn_cast<DecompositionDecl>(DD)) {
+ if (const VarDecl *OrigVar = DecompDecl->getOriginalVar().Var) {
+ auto It = LocalDeclMap.find(OrigVar->getCanonicalDecl());
+ if (It != LocalDeclMap.end())
+ // Original variable is mapped, use it instead.
+ TargetDecl = OrigVar;
+ }
+ }
+
+ // Use getNonReferenceType() because we need the actual object type, not the
+ // reference type. DeclRefExpr with VK_LValue requires a non-reference type
+ // (AST invariant). EmitDeclRefLValue will load any reference for us.
+ QualType DREType = TargetDecl->getType().getNonReferenceType();
+ DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(TargetDecl),
+ /*RefersToEnclosingVariableOrCapture=*/true, DREType,
+ VK_LValue, SourceLocation());
+ LValue BaseLVal = EmitDeclRefLValue(&DRE);
+
+ // Ensure the Address has the correct element type for DD's type.
+ // EmitDeclRefLValue might return an address with a different element type
+ // if TargetDecl != DD or if reference unwrapping occurred.
+ Address BaseAddr = BaseLVal.getAddress();
+ QualType DDType = DD->getType();
+ llvm::Type *ExpectedTy = CGM.getTypes().ConvertTypeForMem(DDType);
+ if (BaseAddr.getElementType() != ExpectedTy)
+ BaseAddr = BaseAddr.withElementType(ExpectedTy);
----------------
zahiraam wrote:
Removing these lines resulted in a crash in` CreateStructGEP` for
`test_target_parallel` in `structured-binding-codegen.cpp`:
Step-by-step failure without the element type adjustment:
1. Line 3647: `EmitDeclRefLValueWithElementType(TargetDecl, DD->getType())`
- `TargetDecl` may be the original variable (from `getOriginalVar()`)
- In target regions, captured parameters have LLVM representation that may
not preserve the precise struct type
- Without element type adjustment: `Address` has incorrect element type
(not `%struct.Point`)
2. Line 3666: `EmitLValue(BindingExpr)` where `BindingExpr` accesses field `x`
- Calls `EmitLValueForField` -> `emitAddrOfFieldStorage` ->
`CreateStructGEP`
3. Line 231 in `CGBuilder.h: CreateStructGEP` does:
`cast<StructType>(Addr.getElementType())` // <- crashes here.
- Tries to cast element type to `StructType`
- Element type is not `%struct.Point` (may be opaque pointer or different
representation)
- Assertion fails: "cast() argument of incompatible type!"
The `withElementType()` call only updates LLVM type metadata - it doesn't emit
any code or change the pointer value. We need it because when accessing the
decomposition through `OrigVar` in target regions, the address has the correct
memory layout but may lack precise type information due to how target region
captures work. We're correcting the LLVM type metadata to match the actual
struct type so `CreateStructGEP` succeeds. The underlying memory is correct. We
are just restoring the type annotation.
Alternatives:
Option 1: Don't use OrigVar - always capture DD directly. The problem is that
even when we always use
DD directly, EmitDeclRefLValue can still return an address with the wrong
element type in some contexts (templates, different instantiation paths,
etc.). So, this doesn't fully eliminate the need for the type adjustment, but
simplifies the code.
Option 2: Fix target region codegen to preserve struct types for all captures
For that we would need to modify `EmitDeclRefLValue` or target region capture
emission to maintain precise LLVM struct types instead of using opaque
pointers. This requires refactoring how OpenMP target regions handle captured
parameters
globally, affecting all captures not just decompositions.
Option 3: Emit a bitcast instead of `withElementType`
`Address Addr = ...;`
`if (Addr.getElementType() != ExpectedTy) {`
`llvm::Value *Casted = Builder.CreateBitCast(Addr.getPointer(),`
`ExpectedTy->getPointerTo());`
`Addr = Address(Casted, ExpectedTy, Addr.getAlignment());`
` }`
This emits unnecessary bitcast instructions in IR when the pointer is already
correct. This might generate worse IR.
Option 4: The current approach WithElementType.
Please advise with the best course of action.
https://github.com/llvm/llvm-project/pull/190832
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits