mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-30 15:10:59 +03:00
Merge remote-tracking branch 'origin/master' into merge-2.110
This commit is contained in:
commit
c271cf9fae
6 changed files with 79 additions and 17 deletions
|
@ -5,6 +5,7 @@
|
|||
#### Platform support
|
||||
|
||||
#### Bug fixes
|
||||
- Fix potentially corrupt IR layouts for bit fields. (#4646, #4708)
|
||||
|
||||
# LDC 1.39.0 (2024-07-04)
|
||||
|
||||
|
|
|
@ -183,6 +183,7 @@ DRValue *DBitFieldLValue::getRVal() {
|
|||
const auto sizeInBits = intType->getBitWidth();
|
||||
const auto ptr = val;
|
||||
LLValue *v = gIR->ir->CreateAlignedLoad(intType, ptr, llvm::MaybeAlign(1));
|
||||
// TODO: byte-swap v for big-endian targets?
|
||||
|
||||
if (bf->type->isunsigned()) {
|
||||
if (auto n = bf->bitOffset)
|
||||
|
@ -212,6 +213,7 @@ void DBitFieldLValue::store(LLValue *value) {
|
|||
llvm::APInt::getLowBitsSet(intType->getBitWidth(), bf->fieldWidth);
|
||||
const auto oldVal =
|
||||
gIR->ir->CreateAlignedLoad(intType, ptr, llvm::MaybeAlign(1));
|
||||
// TODO: byte-swap oldVal for big-endian targets?
|
||||
const auto maskedOldVal =
|
||||
gIR->ir->CreateAnd(oldVal, ~(mask << bf->bitOffset));
|
||||
|
||||
|
@ -221,6 +223,7 @@ void DBitFieldLValue::store(LLValue *value) {
|
|||
bfVal = gIR->ir->CreateShl(bfVal, n);
|
||||
|
||||
const auto newVal = gIR->ir->CreateOr(maskedOldVal, bfVal);
|
||||
// TODO: byte-swap newVal for big-endian targets?
|
||||
gIR->ir->CreateAlignedStore(newVal, ptr, llvm::MaybeAlign(1));
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
|
|||
// get a pointer to this group's IR field
|
||||
const auto ptr = DtoLVal(DtoIndexAggregate(mem, sd, vd));
|
||||
|
||||
// merge all initializers to a single value
|
||||
// merge all initializers to a single integer value
|
||||
const auto intType =
|
||||
LLIntegerType::get(gIR->context(), group.sizeInBytes * 8);
|
||||
LLValue *val = LLConstant::getNullValue(intType);
|
||||
|
@ -165,6 +165,7 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
|
|||
}
|
||||
|
||||
IF_LOG Logger::cout() << "merged IR value: " << *val << '\n';
|
||||
// TODO: byte-swap val for big-endian targets?
|
||||
gIR->ir->CreateAlignedStore(val, ptr, llvm::MaybeAlign(1));
|
||||
offset += group.sizeInBytes;
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "ir/irtypeclass.h"
|
||||
#include "ir/irtypestruct.h"
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace dmd;
|
||||
|
||||
|
@ -257,6 +258,8 @@ void IrAggr::addFieldInitializers(
|
|||
const VarInitMap &explicitInitializers, AggregateDeclaration *decl,
|
||||
unsigned &offset, unsigned &interfaceVtblIndex, bool &isPacked) {
|
||||
|
||||
using llvm::APInt;
|
||||
|
||||
if (ClassDeclaration *cd = decl->isClassDeclaration()) {
|
||||
if (cd->baseClass) {
|
||||
addFieldInitializers(constants, explicitInitializers, cd->baseClass,
|
||||
|
@ -302,6 +305,9 @@ void IrAggr::addFieldInitializers(
|
|||
: getDefaultInitializer(field);
|
||||
};
|
||||
|
||||
// IR field index => APInt for bitfield group
|
||||
std::unordered_map<unsigned, APInt> bitFieldGroupConstants;
|
||||
|
||||
const auto addToBitFieldGroup = [&](BitFieldDeclaration *bf,
|
||||
unsigned fieldIndex, unsigned bitOffset) {
|
||||
LLConstant *init = getFieldInit(bf);
|
||||
|
@ -310,20 +316,24 @@ void IrAggr::addFieldInitializers(
|
|||
return;
|
||||
}
|
||||
|
||||
LLConstant *&constant = constants[baseLLFieldIndex + fieldIndex];
|
||||
if (bitFieldGroupConstants.find(fieldIndex) ==
|
||||
bitFieldGroupConstants.end()) {
|
||||
const auto fieldType =
|
||||
llvm::cast<LLArrayType>(b.defaultTypes()[fieldIndex]); // an i8 array
|
||||
const auto bitFieldSize = fieldType->getNumElements();
|
||||
bitFieldGroupConstants.emplace(fieldIndex, APInt(bitFieldSize * 8, 0));
|
||||
}
|
||||
|
||||
using llvm::APInt;
|
||||
const auto fieldType = b.defaultTypes()[fieldIndex];
|
||||
const auto intSizeInBits = fieldType->getIntegerBitWidth();
|
||||
const APInt oldVal =
|
||||
constant ? constant->getUniqueInteger() : APInt(intSizeInBits, 0);
|
||||
APInt &constant = bitFieldGroupConstants[fieldIndex];
|
||||
const auto intSizeInBits = constant.getBitWidth();
|
||||
|
||||
const APInt oldVal = constant;
|
||||
const APInt bfVal = init->getUniqueInteger().zextOrTrunc(intSizeInBits);
|
||||
const APInt mask = APInt::getLowBitsSet(intSizeInBits, bf->fieldWidth)
|
||||
<< bitOffset;
|
||||
assert(!oldVal.intersects(mask) && "has masked bits set already");
|
||||
const APInt newVal = oldVal | ((bfVal << bitOffset) & mask);
|
||||
|
||||
constant = LLConstant::getIntegerValue(fieldType, newVal);
|
||||
constant = oldVal | ((bfVal << bitOffset) & mask);
|
||||
};
|
||||
|
||||
// add explicit and non-overlapping implicit initializers
|
||||
|
@ -333,7 +343,7 @@ void IrAggr::addFieldInitializers(
|
|||
const auto fieldIndex = pair.second;
|
||||
|
||||
if (auto bf = field->isBitFieldDeclaration()) {
|
||||
// multiple bit fields can map to a single IR field (of integer type)
|
||||
// multiple bit fields can map to a single IR field for the whole group
|
||||
addToBitFieldGroup(bf, fieldIndex, bf->bitOffset);
|
||||
} else {
|
||||
LLConstant *&constant = constants[baseLLFieldIndex + fieldIndex];
|
||||
|
@ -356,6 +366,25 @@ void IrAggr::addFieldInitializers(
|
|||
(bf->offset - primary->offset) * 8 + bf->bitOffset);
|
||||
}
|
||||
|
||||
for (const auto &pair : bitFieldGroupConstants) {
|
||||
const unsigned fieldIndex = pair.first;
|
||||
const APInt intValue = pair.second;
|
||||
|
||||
LLConstant *&constant = constants[baseLLFieldIndex + fieldIndex];
|
||||
assert(!constant && "already have a constant for a bitfield group?");
|
||||
|
||||
// convert APInt to i8 array
|
||||
const auto i8Type = getI8Type();
|
||||
const auto numBytes = intValue.getBitWidth() / 8;
|
||||
llvm::SmallVector<LLConstant *, 8> bytes;
|
||||
for (unsigned i = 0; i < numBytes; ++i) {
|
||||
APInt byteVal = intValue.extractBits(8, i * 8);
|
||||
bytes.push_back(LLConstant::getIntegerValue(i8Type, byteVal));
|
||||
}
|
||||
|
||||
constant = llvm::ConstantArray::get(LLArrayType::get(i8Type, numBytes), bytes);
|
||||
}
|
||||
|
||||
// TODO: sanity check that all explicit initializers have been dealt with?
|
||||
// (potential issue for bitfields in unions...)
|
||||
|
||||
|
|
|
@ -148,8 +148,9 @@ void AggrTypeBuilder::addAggregate(
|
|||
const uint64_t f_begin = field->offset;
|
||||
const uint64_t f_end = f_begin + fieldSize;
|
||||
|
||||
// use an i8 array for bit field groups
|
||||
const auto llType =
|
||||
isBitField ? LLIntegerType::get(gIR->context(), fieldSize * 8)
|
||||
isBitField ? llvm::ArrayType::get(getI8Type(), fieldSize)
|
||||
: DtoMemType(field->type);
|
||||
|
||||
// check for overlap with existing fields (on a byte level, not bits)
|
||||
|
@ -214,13 +215,9 @@ void AggrTypeBuilder::addAggregate(
|
|||
fieldSize = af.size;
|
||||
} else {
|
||||
fieldAlignment = getABITypeAlign(llType);
|
||||
if (vd->isBitFieldDeclaration()) {
|
||||
fieldSize = af.size; // an IR integer of possibly non-power-of-2 size
|
||||
} else {
|
||||
fieldSize = getTypeAllocSize(llType);
|
||||
assert(fieldSize <= af.size);
|
||||
}
|
||||
}
|
||||
|
||||
// advance offset to right past this field
|
||||
if (!m_packed) {
|
||||
|
|
31
tests/compilable/gh4646.d
Normal file
31
tests/compilable/gh4646.d
Normal file
|
@ -0,0 +1,31 @@
|
|||
// RUN: %ldc -c -preview=bitfields %s
|
||||
|
||||
struct BitField {
|
||||
uint _0 : 1;
|
||||
uint _1 : 1;
|
||||
uint _2 : 1;
|
||||
uint _3 : 1;
|
||||
uint _4 : 1;
|
||||
uint _5 : 1;
|
||||
uint _6 : 1;
|
||||
uint _7 : 1;
|
||||
uint _8 : 1;
|
||||
uint _9 : 1;
|
||||
uint _10 : 1;
|
||||
uint _11 : 1;
|
||||
uint _12 : 1;
|
||||
uint _13 : 1;
|
||||
uint _14 : 1;
|
||||
uint _15 : 1;
|
||||
uint _16 : 1;
|
||||
}
|
||||
|
||||
static assert(BitField.sizeof == 4);
|
||||
static assert(BitField.alignof == 4);
|
||||
|
||||
struct Foo {
|
||||
BitField bf;
|
||||
}
|
||||
|
||||
static assert(Foo.sizeof == 4);
|
||||
static assert(Foo.alignof == 4);
|
Loading…
Add table
Add a link
Reference in a new issue