Skip to content

Commit 6eef4a3

Browse files
authored
Merge pull request swiftlang#26184 from linux-on-ibm-z/extract-value
IRGen: simplify enum payload value extraction using gather bits
2 parents 7add744 + 8b3c1a4 commit 6eef4a3

File tree

2 files changed

+44
-61
lines changed

2 files changed

+44
-61
lines changed

lib/IRGen/EnumPayload.cpp

Lines changed: 40 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -198,67 +198,37 @@ void EnumPayload::insertValue(IRGenFunction &IGF, llvm::Value *value,
198198

199199
llvm::Value *EnumPayload::extractValue(IRGenFunction &IGF, llvm::Type *type,
200200
unsigned payloadOffset) const {
201-
llvm::Value *result = nullptr;
202-
withValueInPayload(IGF, *this, type, -1, payloadOffset,
203-
[&](LazyValue &payloadValue,
204-
unsigned payloadBitWidth,
205-
unsigned payloadValueOffset,
206-
unsigned valueBitWidth,
207-
unsigned valueOffset) {
208-
auto payloadType = getPayloadType(payloadValue);
209-
// If the desired type matches the payload slot exactly, we don't need
210-
// to do anything.
211-
if (payloadValueOffset == 0 && valueOffset == 0) {
212-
if (type == payloadType) {
213-
result = forcePayloadValue(payloadValue);
214-
return;
215-
}
216-
// If only the width matches exactly, do a bitcast.
217-
if (payloadBitWidth == valueBitWidth) {
218-
result =
219-
IGF.Builder.CreateBitOrPointerCast(forcePayloadValue(payloadValue),
220-
type);
221-
return;
222-
}
223-
}
224-
225-
// Integrate the chunk of payload into the result value.
226-
auto value = forcePayloadValue(payloadValue);
227-
auto valueIntTy =
228-
llvm::IntegerType::get(IGF.IGM.getLLVMContext(), valueBitWidth);
229-
auto payloadIntTy =
230-
llvm::IntegerType::get(IGF.IGM.getLLVMContext(), payloadBitWidth);
231-
232-
value = IGF.Builder.CreateBitOrPointerCast(value, payloadIntTy);
233-
if (IGF.IGM.Triple.isLittleEndian()) {
234-
if (payloadValueOffset > 0)
235-
value = IGF.Builder.CreateLShr(value,
236-
llvm::ConstantInt::get(value->getType(), payloadValueOffset));
237-
} else {
238-
if ((valueBitWidth == 32 || valueBitWidth == 16 || valueBitWidth == 8 || valueBitWidth == 1) &&
239-
payloadBitWidth > (payloadValueOffset + valueBitWidth)) {
240-
unsigned shiftBitWidth = valueBitWidth;
241-
if (valueBitWidth == 1) {
242-
shiftBitWidth = 8;
243-
}
244-
value = IGF.Builder.CreateLShr(value,
245-
llvm::ConstantInt::get(value->getType(), (payloadBitWidth - shiftBitWidth) - payloadValueOffset));
246-
}
247-
}
248-
if (valueBitWidth > payloadBitWidth)
249-
value = IGF.Builder.CreateZExt(value, valueIntTy);
250-
if (valueOffset > 0)
251-
value = IGF.Builder.CreateShl(value,
252-
llvm::ConstantInt::get(value->getType(), valueOffset));
253-
if (valueBitWidth < payloadBitWidth)
254-
value = IGF.Builder.CreateTrunc(value, valueIntTy);
255-
256-
if (!result)
257-
result = value;
258-
else
259-
result = IGF.Builder.CreateOr(result, value);
260-
});
261-
return IGF.Builder.CreateBitOrPointerCast(result, type);
201+
auto &DL = IGF.IGM.DataLayout;
202+
auto &C = IGF.IGM.getLLVMContext();
203+
204+
// Create a mask for the bytes that make up the stored value by
205+
// by zero extending the value mask to its storage size.
206+
// This makes the mask valid regardless of endianness.
207+
auto valueSize = DL.getTypeSizeInBits(type);
208+
auto valueMask = APInt::getLowBitsSet(DL.getTypeStoreSizeInBits(type),
209+
valueSize);
210+
211+
// Pad the valueMask so that it can be applied to the entire
212+
// payload.
213+
auto payloadMask = APInt::getNullValue(getAllocSizeInBits(DL));
214+
payloadMask.insertBits(valueMask, payloadOffset);
215+
216+
// Convert the payload mask into a SpareBitVector.
217+
// TODO: make emitGatherSpareBits take an APInt and delete.
218+
auto mask = SpareBitVector::fromAPInt(std::move(payloadMask));
219+
220+
// Gather the value from the payload.
221+
auto value = emitGatherSpareBits(IGF, mask, 0, valueSize);
222+
223+
// Convert the integer value to the required type.
224+
if (DL.getTypeSizeInBits(value->getType()) > valueSize) {
225+
auto intTy = llvm::IntegerType::get(C, valueSize);
226+
value = IGF.Builder.CreateTrunc(value, intTy);
227+
}
228+
if (value->getType() != type) {
229+
value = IGF.Builder.CreateBitOrPointerCast(value, type);
230+
}
231+
return value;
262232
}
263233

264234
EnumPayload EnumPayload::fromExplosion(IRGenModule &IGM,
@@ -625,3 +595,12 @@ EnumPayload::emitGatherSpareBits(IRGenFunction &IGF,
625595
return llvm::ConstantInt::get(destTy, 0);
626596
return spareBitValue;
627597
}
598+
599+
unsigned EnumPayload::getAllocSizeInBits(const llvm::DataLayout &DL) const {
600+
unsigned size = 0u;
601+
for (const auto &pv : PayloadValues) {
602+
size += DL.getTypeAllocSizeInBits(getPayloadType(pv));
603+
assert(size % 8 == 0 && "allocation size must be a multiple of bytes");
604+
}
605+
return size;
606+
}

lib/IRGen/EnumPayload.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ class EnumPayload {
164164
const SpareBitVector &spareBits,
165165
unsigned firstBitOffset,
166166
unsigned bitWidth) const;
167+
private:
168+
/// Calculate the total number of bits this payload requires.
169+
/// This will always be a multiple of 8.
170+
unsigned getAllocSizeInBits(const llvm::DataLayout &DL) const;
167171
};
168172

169173
}

0 commit comments

Comments
 (0)