@@ -95,44 +95,86 @@ static void moveConstantAllocasToEntryBlock(
9595 }
9696}
9797
98+ // / Tries to find and return the alignment of the pointer `value` by looking for
99+ // / an alignment attribute on the defining allocation op or function argument.
100+ // / If no such attribute is found, returns 1 (i.e., assume that no alignment is
101+ // / guaranteed).
102+ static unsigned getAlignmentOf (Value value) {
103+ if (Operation *definingOp = value.getDefiningOp ()) {
104+ if (auto alloca = dyn_cast<LLVM::AllocaOp>(definingOp))
105+ return alloca.getAlignment ().value_or (1 );
106+ if (auto addressOf = dyn_cast<LLVM::AddressOfOp>(definingOp))
107+ if (auto global = SymbolTable::lookupNearestSymbolFrom<LLVM::GlobalOp>(
108+ definingOp, addressOf.getGlobalNameAttr ()))
109+ return global.getAlignment ().value_or (1 );
110+ // We don't currently handle this operation; assume no alignment.
111+ return 1 ;
112+ }
113+ // Since there is no defining op, this is a block argument. Probably this
114+ // comes directly from a function argument, so check that this is the case.
115+ Operation *parentOp = value.getParentBlock ()->getParentOp ();
116+ if (auto func = dyn_cast<LLVM::LLVMFuncOp>(parentOp)) {
117+ // Use the alignment attribute set for this argument in the parent
118+ // function if it has been set.
119+ auto blockArg = value.cast <BlockArgument>();
120+ if (Attribute alignAttr = func.getArgAttr (
121+ blockArg.getArgNumber (), LLVM::LLVMDialect::getAlignAttrName ()))
122+ return cast<IntegerAttr>(alignAttr).getValue ().getLimitedValue ();
123+ }
124+ // We didn't find anything useful; assume no alignment.
125+ return 1 ;
126+ }
127+
128+ // / Copies the data from a byval pointer argument into newly alloca'ed memory
129+ // / and returns the value of the alloca.
130+ static Value handleByValArgumentInit (OpBuilder &builder, Location loc,
131+ Value argument, Type elementType,
132+ unsigned elementTypeSize,
133+ unsigned targetAlignment) {
134+ // Allocate the new value on the stack.
135+ Value one = builder.create <LLVM::ConstantOp>(loc, builder.getI64Type (),
136+ builder.getI64IntegerAttr (1 ));
137+ Value allocaOp = builder.create <LLVM::AllocaOp>(
138+ loc, argument.getType (), elementType, one, targetAlignment);
139+ // Copy the pointee to the newly allocated value.
140+ Value copySize = builder.create <LLVM::ConstantOp>(
141+ loc, builder.getI64Type (), builder.getI64IntegerAttr (elementTypeSize));
142+ Value isVolatile = builder.create <LLVM::ConstantOp>(
143+ loc, builder.getI1Type (), builder.getBoolAttr (false ));
144+ builder.create <LLVM::MemcpyOp>(loc, allocaOp, argument, copySize, isVolatile);
145+ return allocaOp;
146+ }
147+
148+ // / Handles a function argument marked with the byval attribute by introducing a
149+ // / memcpy if necessary, either due to the pointee being writeable in the
150+ // / callee, and/or due to an alignment mismatch. `requestedAlignment` specifies
151+ // / the alignment set in the "align" argument attribute (or 1 if no align
152+ // / attribute was set).
98153static Value handleByValArgument (OpBuilder &builder, Operation *callable,
99- Value argument,
100- NamedAttribute byValAttribute ) {
154+ Value argument, Type elementType,
155+ unsigned requestedAlignment ) {
101156 auto func = cast<LLVM::LLVMFuncOp>(callable);
102157 LLVM::MemoryEffectsAttr memoryEffects = func.getMemoryAttr ();
103158 // If there is no memory effects attribute, assume that the function is
104159 // not read-only.
105160 bool isReadOnly = memoryEffects &&
106161 memoryEffects.getArgMem () != LLVM::ModRefInfo::ModRef &&
107162 memoryEffects.getArgMem () != LLVM::ModRefInfo::Mod;
108- if (isReadOnly)
163+ // Check if there's an alignment mismatch requiring us to copy.
164+ DataLayout dataLayout (callable->getParentOfType <DataLayoutOpInterface>());
165+ unsigned minimumAlignment = dataLayout.getTypeABIAlignment (elementType);
166+ if (isReadOnly && (requestedAlignment <= minimumAlignment ||
167+ getAlignmentOf (argument) >= requestedAlignment))
109168 return argument;
110- // Resolve the pointee type and its size.
111- auto ptrType = cast<LLVM::LLVMPointerType>(argument.getType ());
112- Type elementType = cast<TypeAttr>(byValAttribute.getValue ()).getValue ();
113- unsigned int typeSize =
114- DataLayout (callable->getParentOfType <DataLayoutOpInterface>())
115- .getTypeSize (elementType);
116- // Allocate the new value on the stack.
117- Value one = builder.create <LLVM::ConstantOp>(
118- func.getLoc (), builder.getI64Type (), builder.getI64IntegerAttr (1 ));
119- Value allocaOp =
120- builder.create <LLVM::AllocaOp>(func.getLoc (), ptrType, elementType, one);
121- // Copy the pointee to the newly allocated value.
122- Value copySize = builder.create <LLVM::ConstantOp>(
123- func.getLoc (), builder.getI64Type (), builder.getI64IntegerAttr (typeSize));
124- Value isVolatile = builder.create <LLVM::ConstantOp>(
125- func.getLoc (), builder.getI1Type (), builder.getBoolAttr (false ));
126- builder.create <LLVM::MemcpyOp>(func.getLoc (), allocaOp, argument, copySize,
127- isVolatile);
128- return allocaOp;
169+ unsigned targetAlignment = std::max (requestedAlignment, minimumAlignment);
170+ return handleByValArgumentInit (builder, func.getLoc (), argument, elementType,
171+ dataLayout.getTypeSize (elementType),
172+ targetAlignment);
129173}
130174
131175// / Returns true if the given argument or result attribute is supported by the
132176// / inliner, false otherwise.
133177static bool isArgOrResAttrSupported (NamedAttribute attr) {
134- if (attr.getName () == LLVM::LLVMDialect::getAlignAttrName ())
135- return false ;
136178 if (attr.getName () == LLVM::LLVMDialect::getInAllocaAttrName ())
137179 return false ;
138180 if (attr.getName () == LLVM::LLVMDialect::getNoAliasAttrName ())
@@ -289,9 +331,19 @@ struct LLVMInlinerInterface : public DialectInlinerInterface {
289331 Value handleArgument (OpBuilder &builder, Operation *call, Operation *callable,
290332 Value argument, Type targetType,
291333 DictionaryAttr argumentAttrs) const final {
292- if (auto attr =
293- argumentAttrs.getNamed (LLVM::LLVMDialect::getByValAttrName ()))
294- return handleByValArgument (builder, callable, argument, *attr);
334+ if (std::optional<NamedAttribute> attr =
335+ argumentAttrs.getNamed (LLVM::LLVMDialect::getByValAttrName ())) {
336+ Type elementType = cast<TypeAttr>(attr->getValue ()).getValue ();
337+ unsigned requestedAlignment = 1 ;
338+ if (std::optional<NamedAttribute> alignAttr =
339+ argumentAttrs.getNamed (LLVM::LLVMDialect::getAlignAttrName ())) {
340+ requestedAlignment = cast<IntegerAttr>(alignAttr->getValue ())
341+ .getValue ()
342+ .getLimitedValue ();
343+ }
344+ return handleByValArgument (builder, callable, argument, elementType,
345+ requestedAlignment);
346+ }
295347 return argument;
296348 }
297349
0 commit comments