mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-03 00:20:40 +03:00
Fix array casts with constant source lengths
The `__ArrayCast` lowering isn't (always?) done when casting a static array to a slice with different element size. So exploit constant source lengths and compute the target length at compile-time. This fixes compilable/ldc_github_421.d - a float[16] can be cast to a float4[] with constant length 4.
This commit is contained in:
parent
0e2173bf82
commit
9469c6b5b8
1 changed files with 16 additions and 17 deletions
|
@ -1263,38 +1263,37 @@ DValue *DtoCastArray(Loc &loc, DValue *u, Type *to) {
|
||||||
LLValue *length = nullptr;
|
LLValue *length = nullptr;
|
||||||
LLValue *ptr = nullptr;
|
LLValue *ptr = nullptr;
|
||||||
if (fromtype->ty == Tsarray) {
|
if (fromtype->ty == Tsarray) {
|
||||||
uinteger_t len = static_cast<TypeSArray *>(fromtype)->dim->toUInteger();
|
length = DtoConstSize_t(
|
||||||
length = DtoConstSize_t(len);
|
static_cast<TypeSArray *>(fromtype)->dim->toUInteger());
|
||||||
ptr = DtoLVal(u);
|
ptr = DtoLVal(u);
|
||||||
assert(isaPointer(ptr->getType()));
|
|
||||||
LLArrayType *arrty = isaArray(ptr->getType()->getContainedType(0));
|
|
||||||
|
|
||||||
if (arrty->getNumElements() * fromtype->nextOf()->size() %
|
|
||||||
totype->nextOf()->size() !=
|
|
||||||
0) {
|
|
||||||
error(loc,
|
|
||||||
"invalid cast from `%s` to `%s`, the element sizes don't line up",
|
|
||||||
fromtype->toChars(), totype->toChars());
|
|
||||||
fatal();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
length = DtoArrayLen(u);
|
length = DtoArrayLen(u);
|
||||||
ptr = DtoArrayPtr(u);
|
ptr = DtoArrayPtr(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLType *ptrty = DtoArrayType(totype)->getContainedType(1);
|
|
||||||
|
|
||||||
const auto fsize = fromtype->nextOf()->size();
|
const auto fsize = fromtype->nextOf()->size();
|
||||||
const auto tsize = totype->nextOf()->size();
|
const auto tsize = totype->nextOf()->size();
|
||||||
if (fsize != tsize) {
|
if (fsize != tsize) {
|
||||||
if (fsize % tsize == 0) {
|
if (auto constLength = isaConstantInt(length)) {
|
||||||
// set new length to `length * (fsize / tsize)`
|
// compute new constant length: (constLength * fsize) / tsize
|
||||||
|
const auto totalSize = constLength->getZExtValue() * fsize;
|
||||||
|
if (totalSize % tsize != 0) {
|
||||||
|
error(loc,
|
||||||
|
"invalid cast from `%s` to `%s`, the element sizes don't "
|
||||||
|
"line up",
|
||||||
|
fromtype->toChars(), totype->toChars());
|
||||||
|
fatal();
|
||||||
|
}
|
||||||
|
length = DtoConstSize_t(totalSize / tsize);
|
||||||
|
} else if (fsize % tsize == 0) {
|
||||||
|
// compute new dynamic length: length * (fsize / tsize)
|
||||||
length = gIR->ir->CreateMul(length, DtoConstSize_t(fsize / tsize));
|
length = gIR->ir->CreateMul(length, DtoConstSize_t(fsize / tsize));
|
||||||
} else {
|
} else {
|
||||||
llvm_unreachable("should have been lowered to `__ArrayCast`");
|
llvm_unreachable("should have been lowered to `__ArrayCast`");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLType *ptrty = tolltype->getStructElementType(1);
|
||||||
return new DSliceValue(to, length, DtoBitCast(ptr, ptrty));
|
return new DSliceValue(to, length, DtoBitCast(ptr, ptrty));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue