@@ -113,7 +113,7 @@ bool LLVM::LoadOp::loadsFrom(const MemorySlot &slot) {
113
113
bool LLVM::LoadOp::storesTo (const MemorySlot &slot) { return false ; }
114
114
115
115
Value LLVM::LoadOp::getStored (const MemorySlot &slot, RewriterBase &rewriter,
116
- const DataLayout &dataLayout) {
116
+ Value reachingDef, const DataLayout &dataLayout) {
117
117
llvm_unreachable (" getStored should not be called on LoadOp" );
118
118
}
119
119
@@ -144,7 +144,7 @@ static bool isSupportedTypeForConversion(Type type) {
144
144
// / Checks that `rhs` can be converted to `lhs` by a sequence of casts and
145
145
// / truncations.
146
146
static bool areConversionCompatible (const DataLayout &layout, Type targetType,
147
- Type srcType) {
147
+ Type srcType, bool allowWidening = false ) {
148
148
if (targetType == srcType)
149
149
return true ;
150
150
@@ -158,7 +158,8 @@ static bool areConversionCompatible(const DataLayout &layout, Type targetType,
158
158
isa<LLVM::LLVMPointerType>(srcType))
159
159
return layout.getTypeSize (targetType) == layout.getTypeSize (srcType);
160
160
161
- return layout.getTypeSize (targetType) <= layout.getTypeSize (srcType);
161
+ return allowWidening ||
162
+ layout.getTypeSize (targetType) <= layout.getTypeSize (srcType);
162
163
}
163
164
164
165
// / Checks if `dataLayout` describes a little endian layout.
@@ -170,6 +171,35 @@ static bool isBigEndian(const DataLayout &dataLayout) {
170
171
// / The size of a byte in bits.
171
172
constexpr const static uint64_t kBitsInByte = 8 ;
172
173
174
+ // / Converts a value to an integer type of the same size.
175
+ // / Assumes that the type can be converted.
176
+ static Value convertToIntValue (RewriterBase &rewriter, Location loc, Value val,
177
+ const DataLayout &dataLayout) {
178
+ Type type = val.getType ();
179
+ assert (isSupportedTypeForConversion (type));
180
+
181
+ if (isa<IntegerType>(type))
182
+ return val;
183
+
184
+ uint64_t typeBitSize = dataLayout.getTypeSizeInBits (type);
185
+ IntegerType valueSizeInteger = rewriter.getIntegerType (typeBitSize);
186
+
187
+ if (isa<LLVM::LLVMPointerType>(type))
188
+ return rewriter.createOrFold <LLVM::PtrToIntOp>(loc, valueSizeInteger, val);
189
+ return rewriter.createOrFold <LLVM::BitcastOp>(loc, valueSizeInteger, val);
190
+ }
191
+
192
+ // / Converts an value with an integer type to `targetType`.
193
+ static Value convertIntValueToType (RewriterBase &rewriter, Location loc,
194
+ Value val, Type targetType) {
195
+ assert (isa<IntegerType>(val.getType ()));
196
+ if (val.getType () == targetType)
197
+ return val;
198
+ if (isa<LLVM::LLVMPointerType>(targetType))
199
+ return rewriter.createOrFold <LLVM::IntToPtrOp>(loc, targetType, val);
200
+ return rewriter.createOrFold <LLVM::BitcastOp>(loc, targetType, val);
201
+ }
202
+
173
203
// / Constructs operations that convert `inputValue` into a new value of type
174
204
// / `targetType`. Assumes that this conversion is possible.
175
205
static Value createConversionSequence (RewriterBase &rewriter, Location loc,
@@ -196,17 +226,8 @@ static Value createConversionSequence(RewriterBase &rewriter, Location loc,
196
226
return rewriter.createOrFold <LLVM::AddrSpaceCastOp>(loc, targetType,
197
227
srcValue);
198
228
199
- IntegerType valueSizeInteger =
200
- rewriter.getIntegerType (srcTypeSize * kBitsInByte );
201
- Value replacement = srcValue;
202
-
203
229
// First, cast the value to a same-sized integer type.
204
- if (isa<LLVM::LLVMPointerType>(srcType))
205
- replacement = rewriter.createOrFold <LLVM::PtrToIntOp>(loc, valueSizeInteger,
206
- replacement);
207
- else if (replacement.getType () != valueSizeInteger)
208
- replacement = rewriter.createOrFold <LLVM::BitcastOp>(loc, valueSizeInteger,
209
- replacement);
230
+ Value replacement = convertToIntValue (rewriter, loc, srcValue, dataLayout);
210
231
211
232
// Truncate the integer if the size of the target is less than the value.
212
233
if (targetTypeSize != srcTypeSize) {
@@ -224,20 +245,67 @@ static Value createConversionSequence(RewriterBase &rewriter, Location loc,
224
245
}
225
246
226
247
// Now cast the integer to the actual target type if required.
227
- if (isa<LLVM::LLVMPointerType>(targetType))
228
- replacement =
229
- rewriter.createOrFold <LLVM::IntToPtrOp>(loc, targetType, replacement);
230
- else if (replacement.getType () != targetType)
231
- replacement =
232
- rewriter.createOrFold <LLVM::BitcastOp>(loc, targetType, replacement);
233
-
234
- return replacement;
248
+ return convertIntValueToType (rewriter, loc, replacement, targetType);
235
249
}
236
250
237
251
Value LLVM::StoreOp::getStored (const MemorySlot &slot, RewriterBase &rewriter,
252
+ Value reachingDef,
238
253
const DataLayout &dataLayout) {
239
- return createConversionSequence (rewriter, getLoc (), getValue (), slot.elemType ,
240
- dataLayout);
254
+ uint64_t valueTypeSize = dataLayout.getTypeSizeInBits (getValue ().getType ());
255
+ uint64_t slotTypeSize = dataLayout.getTypeSizeInBits (slot.elemType );
256
+ if (slotTypeSize <= valueTypeSize)
257
+ return createConversionSequence (rewriter, getLoc (), getValue (),
258
+ slot.elemType , dataLayout);
259
+
260
+ assert (reachingDef && reachingDef.getType () == slot.elemType &&
261
+ " expected the reaching definition's type to slot's type" );
262
+
263
+ // In the case where the store only overwrites parts of the memory,
264
+ // bit fiddling is required to construct the new value.
265
+
266
+ // First convert both values to integers of the same size.
267
+ Value defAsInt =
268
+ convertToIntValue (rewriter, getLoc (), reachingDef, dataLayout);
269
+ Value valueAsInt =
270
+ convertToIntValue (rewriter, getLoc (), getValue (), dataLayout);
271
+ // Extend the value to the size of the reaching definition.
272
+ valueAsInt = rewriter.createOrFold <LLVM::ZExtOp>(getLoc (), defAsInt.getType (),
273
+ valueAsInt);
274
+ uint64_t sizeDifference = slotTypeSize - valueTypeSize;
275
+ if (isBigEndian (dataLayout)) {
276
+ // On big endian systems, a store to the base pointer overwrites the most
277
+ // significant bits. To accomodate for this, the stored value needs to be
278
+ // shifted into the according position.
279
+ Value bigEndianShift = rewriter.create <LLVM::ConstantOp>(
280
+ getLoc (), rewriter.getIntegerAttr (defAsInt.getType (), sizeDifference));
281
+ valueAsInt = rewriter.createOrFold <LLVM::ShlOp>(getLoc (), valueAsInt,
282
+ bigEndianShift);
283
+ }
284
+
285
+ // Construct the mask that is used to erase the bits that are overwritten by
286
+ // the store.
287
+ APInt maskValue;
288
+ if (isBigEndian (dataLayout)) {
289
+ // Build a mask that has the most significant bits set to zero.
290
+ // Note: This is the same as 2^sizeDifference - 1
291
+ maskValue = APInt::getAllOnes (sizeDifference).zext (slotTypeSize);
292
+ } else {
293
+ // Build a mask that has the least significant bits set to zero.
294
+ // Note: This is the same as -(2^valueTypeSize)
295
+ maskValue = APInt::getAllOnes (valueTypeSize).zext (slotTypeSize);
296
+ maskValue.flipAllBits ();
297
+ }
298
+
299
+ // Mask out the affected bits ...
300
+ Value mask = rewriter.create <LLVM::ConstantOp>(
301
+ getLoc (), rewriter.getIntegerAttr (defAsInt.getType (), maskValue));
302
+ Value masked = rewriter.createOrFold <LLVM::AndOp>(getLoc (), defAsInt, mask);
303
+
304
+ // ... and combine the result with the new value.
305
+ Value combined =
306
+ rewriter.createOrFold <LLVM::OrOp>(getLoc (), masked, valueAsInt);
307
+
308
+ return convertIntValueToType (rewriter, getLoc (), combined, slot.elemType );
241
309
}
242
310
243
311
bool LLVM::LoadOp::canUsesBeRemoved (
@@ -283,7 +351,8 @@ bool LLVM::StoreOp::canUsesBeRemoved(
283
351
return blockingUse == slot.ptr && getAddr () == slot.ptr &&
284
352
getValue () != slot.ptr &&
285
353
areConversionCompatible (dataLayout, slot.elemType ,
286
- getValue ().getType ()) &&
354
+ getValue ().getType (),
355
+ /* allowWidening=*/ true ) &&
287
356
!getVolatile_ ();
288
357
}
289
358
@@ -838,6 +907,7 @@ bool LLVM::MemsetOp::storesTo(const MemorySlot &slot) {
838
907
}
839
908
840
909
Value LLVM::MemsetOp::getStored (const MemorySlot &slot, RewriterBase &rewriter,
910
+ Value reachingDef,
841
911
const DataLayout &dataLayout) {
842
912
// TODO: Support non-integer types.
843
913
return TypeSwitch<Type, Value>(slot.elemType )
@@ -1149,6 +1219,7 @@ bool LLVM::MemcpyOp::storesTo(const MemorySlot &slot) {
1149
1219
}
1150
1220
1151
1221
Value LLVM::MemcpyOp::getStored (const MemorySlot &slot, RewriterBase &rewriter,
1222
+ Value reachingDef,
1152
1223
const DataLayout &dataLayout) {
1153
1224
return memcpyGetStored (*this , slot, rewriter);
1154
1225
}
@@ -1199,7 +1270,7 @@ bool LLVM::MemcpyInlineOp::storesTo(const MemorySlot &slot) {
1199
1270
}
1200
1271
1201
1272
Value LLVM::MemcpyInlineOp::getStored (const MemorySlot &slot,
1202
- RewriterBase &rewriter,
1273
+ RewriterBase &rewriter, Value reachingDef,
1203
1274
const DataLayout &dataLayout) {
1204
1275
return memcpyGetStored (*this , slot, rewriter);
1205
1276
}
@@ -1252,6 +1323,7 @@ bool LLVM::MemmoveOp::storesTo(const MemorySlot &slot) {
1252
1323
}
1253
1324
1254
1325
Value LLVM::MemmoveOp::getStored (const MemorySlot &slot, RewriterBase &rewriter,
1326
+ Value reachingDef,
1255
1327
const DataLayout &dataLayout) {
1256
1328
return memcpyGetStored (*this , slot, rewriter);
1257
1329
}
0 commit comments