@@ -95,44 +95,86 @@ static void moveConstantAllocasToEntryBlock(
95
95
}
96
96
}
97
97
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).
98
153
static Value handleByValArgument (OpBuilder &builder, Operation *callable,
99
- Value argument,
100
- NamedAttribute byValAttribute ) {
154
+ Value argument, Type elementType,
155
+ unsigned requestedAlignment ) {
101
156
auto func = cast<LLVM::LLVMFuncOp>(callable);
102
157
LLVM::MemoryEffectsAttr memoryEffects = func.getMemoryAttr ();
103
158
// If there is no memory effects attribute, assume that the function is
104
159
// not read-only.
105
160
bool isReadOnly = memoryEffects &&
106
161
memoryEffects.getArgMem () != LLVM::ModRefInfo::ModRef &&
107
162
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))
109
168
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);
129
173
}
130
174
131
175
// / Returns true if the given argument or result attribute is supported by the
132
176
// / inliner, false otherwise.
133
177
static bool isArgOrResAttrSupported (NamedAttribute attr) {
134
- if (attr.getName () == LLVM::LLVMDialect::getAlignAttrName ())
135
- return false ;
136
178
if (attr.getName () == LLVM::LLVMDialect::getInAllocaAttrName ())
137
179
return false ;
138
180
if (attr.getName () == LLVM::LLVMDialect::getNoAliasAttrName ())
@@ -289,9 +331,19 @@ struct LLVMInlinerInterface : public DialectInlinerInterface {
289
331
Value handleArgument (OpBuilder &builder, Operation *call, Operation *callable,
290
332
Value argument, Type targetType,
291
333
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
+ }
295
347
return argument;
296
348
}
297
349
0 commit comments