mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-07 03:16:05 +03:00
Remove ldc.arrayinit & streamline _d_array_slice_copy/_d_arraycast_len with upstream
This commit is contained in:
parent
b223888c19
commit
33cadfaca6
10 changed files with 106 additions and 94 deletions
|
@ -186,18 +186,27 @@ static Type *DtoArrayElementType(Type *arrayType) {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void copySlice(Loc &loc, LLValue *dstarr, LLValue *sz1, LLValue *srcarr,
|
static LLValue *computeSize(LLValue *length, size_t elementSize) {
|
||||||
LLValue *sz2, bool knownInBounds) {
|
return elementSize == 1
|
||||||
|
? length
|
||||||
|
: gIR->ir->CreateMul(length, DtoConstSize_t(elementSize));
|
||||||
|
};
|
||||||
|
|
||||||
|
static void copySlice(Loc &loc, LLValue *dstarr, LLValue *dstlen, LLValue *srcarr,
|
||||||
|
LLValue *srclen, size_t elementSize, bool knownInBounds) {
|
||||||
const bool checksEnabled =
|
const bool checksEnabled =
|
||||||
global.params.useAssert == CHECKENABLEon || gIR->emitArrayBoundsChecks();
|
global.params.useAssert == CHECKENABLEon || gIR->emitArrayBoundsChecks();
|
||||||
if (checksEnabled && !knownInBounds) {
|
if (checksEnabled && !knownInBounds) {
|
||||||
LLValue *fn = getRuntimeFunction(loc, gIR->module, "_d_array_slice_copy");
|
LLValue *fn = getRuntimeFunction(loc, gIR->module, "_d_array_slice_copy");
|
||||||
gIR->CreateCallOrInvoke(fn, dstarr, sz1, srcarr, sz2);
|
gIR->CreateCallOrInvoke(
|
||||||
|
fn, {dstarr, dstlen, srcarr, srclen, DtoConstSize_t(elementSize)}, "",
|
||||||
|
/*isNothrow=*/true);
|
||||||
} else {
|
} else {
|
||||||
// We might have dstarr == srcarr at compile time, but as long as
|
// We might have dstarr == srcarr at compile time, but as long as
|
||||||
// sz1 == 0 at runtime, this would probably still be legal (the C spec
|
// sz1 == 0 at runtime, this would probably still be legal (the C spec
|
||||||
// is unclear here).
|
// is unclear here).
|
||||||
DtoMemCpy(dstarr, srcarr, sz1);
|
LLValue *size = computeSize(dstlen, elementSize);
|
||||||
|
DtoMemCpy(dstarr, srcarr, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,12 +254,6 @@ void DtoArrayAssign(Loc &loc, DValue *lhs, DValue *rhs, int op,
|
||||||
LLValue *lhsPtr = DtoBitCast(realLhsPtr, getVoidPtrType());
|
LLValue *lhsPtr = DtoBitCast(realLhsPtr, getVoidPtrType());
|
||||||
LLValue *lhsLength = DtoArrayLen(lhs);
|
LLValue *lhsLength = DtoArrayLen(lhs);
|
||||||
|
|
||||||
auto computeSize = [](LLValue *length, size_t elementSize) {
|
|
||||||
return elementSize == 1
|
|
||||||
? length
|
|
||||||
: gIR->ir->CreateMul(length, DtoConstSize_t(elementSize));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Be careful to handle void arrays correctly when modifying this (see tests
|
// Be careful to handle void arrays correctly when modifying this (see tests
|
||||||
// for DMD issue 7493).
|
// for DMD issue 7493).
|
||||||
// TODO: This should use AssignExp::memset.
|
// TODO: This should use AssignExp::memset.
|
||||||
|
@ -268,15 +271,14 @@ void DtoArrayAssign(Loc &loc, DValue *lhs, DValue *rhs, int op,
|
||||||
if (!needsDestruction && !needsPostblit) {
|
if (!needsDestruction && !needsPostblit) {
|
||||||
// fast version
|
// fast version
|
||||||
const size_t elementSize = getTypeAllocSize(DtoMemType(elemType));
|
const size_t elementSize = getTypeAllocSize(DtoMemType(elemType));
|
||||||
LLValue *lhsSize = computeSize(lhsLength, elementSize);
|
|
||||||
|
|
||||||
if (rhs->isNull()) {
|
if (rhs->isNull()) {
|
||||||
|
LLValue *lhsSize = computeSize(lhsLength, elementSize);
|
||||||
DtoMemSetZero(lhsPtr, lhsSize);
|
DtoMemSetZero(lhsPtr, lhsSize);
|
||||||
} else {
|
} else {
|
||||||
LLValue *rhsSize = computeSize(rhsLength, elementSize);
|
|
||||||
const bool knownInBounds =
|
const bool knownInBounds =
|
||||||
isConstructing || (t->ty == Tsarray && t2->ty == Tsarray);
|
isConstructing || (t->ty == Tsarray && t2->ty == Tsarray);
|
||||||
copySlice(loc, lhsPtr, lhsSize, rhsPtr, rhsSize, knownInBounds);
|
copySlice(loc, lhsPtr, lhsLength, rhsPtr, rhsLength, elementSize,
|
||||||
|
knownInBounds);
|
||||||
}
|
}
|
||||||
} else if (isConstructing) {
|
} else if (isConstructing) {
|
||||||
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
||||||
|
@ -912,7 +914,7 @@ DSliceValue *DtoCatArrays(Loc &loc, Type *arrayType, Expression *exp1,
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newArray =
|
auto newArray =
|
||||||
gIR->funcGen().callOrInvoke(fn, args, ".appendedArray").getInstruction();
|
gIR->CreateCallOrInvoke(fn, args, ".appendedArray").getInstruction();
|
||||||
return getSlice(arrayType, newArray);
|
return getSlice(arrayType, newArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,7 +987,7 @@ LLValue *DtoArrayEqCmp_impl(Loc &loc, const char *func, DValue *l,
|
||||||
args.push_back(DtoBitCast(tival, fn->getFunctionType()->getParamType(2)));
|
args.push_back(DtoBitCast(tival, fn->getFunctionType()->getParamType(2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return gIR->funcGen().callOrInvoke(fn, args).getInstruction();
|
return gIR->CreateCallOrInvoke(fn, args).getInstruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When `true` is returned, the type can be compared using `memcmp`.
|
/// When `true` is returned, the type can be compared using `memcmp`.
|
||||||
|
@ -1158,10 +1160,10 @@ LLValue *DtoArrayCastLength(Loc &loc, LLValue *len, LLType *elemty,
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_array_cast_len");
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arraycast_len");
|
||||||
return gIR
|
return gIR
|
||||||
->CreateCallOrInvoke(fn, len, LLConstantInt::get(DtoSize_t(), esz, false),
|
->CreateCallOrInvoke(fn, {len, DtoConstSize_t(esz), DtoConstSize_t(nsz)},
|
||||||
LLConstantInt::get(DtoSize_t(), nsz, false))
|
"", /*isNothrow=*/true)
|
||||||
.getInstruction();
|
.getInstruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,3 +102,44 @@ llvm::BasicBlock *SwitchCaseTargets::getOrCreate(Statement *stmt,
|
||||||
FuncGenState::FuncGenState(IrFunction &irFunc, IRState &irs)
|
FuncGenState::FuncGenState(IrFunction &irFunc, IRState &irs)
|
||||||
: irFunc(irFunc), scopes(irs), jumpTargets(scopes), switchTargets(),
|
: irFunc(irFunc), scopes(irs), jumpTargets(scopes), switchTargets(),
|
||||||
irs(irs) {}
|
irs(irs) {}
|
||||||
|
|
||||||
|
llvm::CallSite FuncGenState::callOrInvoke(llvm::Value *callee,
|
||||||
|
llvm::ArrayRef<llvm::Value *> args,
|
||||||
|
const char *name, bool isNothrow) {
|
||||||
|
// If this is a direct call, we might be able to use the callee attributes
|
||||||
|
// to our advantage.
|
||||||
|
llvm::Function *calleeFn = llvm::dyn_cast<llvm::Function>(callee);
|
||||||
|
|
||||||
|
// Ignore 'nothrow' if there are active catch blocks handling non-Exception
|
||||||
|
// Throwables.
|
||||||
|
if (isNothrow && scopes.isCatchingNonExceptions())
|
||||||
|
isNothrow = false;
|
||||||
|
|
||||||
|
// Intrinsics don't support invoking and 'nounwind' functions don't need it.
|
||||||
|
const bool doesNotThrow =
|
||||||
|
isNothrow ||
|
||||||
|
(calleeFn && (calleeFn->isIntrinsic() || calleeFn->doesNotThrow()));
|
||||||
|
|
||||||
|
// calls inside a funclet must be annotated with its value
|
||||||
|
llvm::SmallVector<llvm::OperandBundleDef, 2> BundleList;
|
||||||
|
|
||||||
|
if (doesNotThrow || scopes.empty()) {
|
||||||
|
llvm::CallInst *call = irs.ir->CreateCall(callee, args, BundleList, name);
|
||||||
|
if (calleeFn) {
|
||||||
|
call->setAttributes(calleeFn->getAttributes());
|
||||||
|
}
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::BasicBlock *landingPad = scopes.getLandingPad();
|
||||||
|
|
||||||
|
llvm::BasicBlock *postinvoke = irs.insertBB("postinvoke");
|
||||||
|
llvm::InvokeInst *invoke = irs.ir->CreateInvoke(
|
||||||
|
callee, postinvoke, landingPad, args, BundleList, name);
|
||||||
|
if (calleeFn) {
|
||||||
|
invoke->setAttributes(calleeFn->getAttributes());
|
||||||
|
}
|
||||||
|
|
||||||
|
irs.scope() = IRScope(postinvoke);
|
||||||
|
return invoke;
|
||||||
|
}
|
||||||
|
|
|
@ -200,51 +200,10 @@ public:
|
||||||
|
|
||||||
/// Emits a call or invoke to the given callee, depending on whether there
|
/// Emits a call or invoke to the given callee, depending on whether there
|
||||||
/// are catches/cleanups active or not.
|
/// are catches/cleanups active or not.
|
||||||
template <typename T>
|
llvm::CallSite callOrInvoke(llvm::Value *callee,
|
||||||
llvm::CallSite callOrInvoke(llvm::Value *callee, const T &args,
|
llvm::ArrayRef<llvm::Value *> args,
|
||||||
const char *name = "", bool isNothrow = false);
|
const char *name = "", bool isNothrow = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IRState &irs;
|
IRState &irs;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
llvm::CallSite FuncGenState::callOrInvoke(llvm::Value *callee, const T &args,
|
|
||||||
const char *name, bool isNothrow) {
|
|
||||||
// If this is a direct call, we might be able to use the callee attributes
|
|
||||||
// to our advantage.
|
|
||||||
llvm::Function *calleeFn = llvm::dyn_cast<llvm::Function>(callee);
|
|
||||||
|
|
||||||
// Ignore 'nothrow' if there are active catch blocks handling non-Exception
|
|
||||||
// Throwables.
|
|
||||||
if (isNothrow && scopes.isCatchingNonExceptions())
|
|
||||||
isNothrow = false;
|
|
||||||
|
|
||||||
// Intrinsics don't support invoking and 'nounwind' functions don't need it.
|
|
||||||
const bool doesNotThrow =
|
|
||||||
isNothrow ||
|
|
||||||
(calleeFn && (calleeFn->isIntrinsic() || calleeFn->doesNotThrow()));
|
|
||||||
|
|
||||||
// calls inside a funclet must be annotated with its value
|
|
||||||
llvm::SmallVector<llvm::OperandBundleDef, 2> BundleList;
|
|
||||||
|
|
||||||
if (doesNotThrow || scopes.empty()) {
|
|
||||||
llvm::CallInst *call = irs.ir->CreateCall(callee, args, BundleList, name);
|
|
||||||
if (calleeFn) {
|
|
||||||
call->setAttributes(calleeFn->getAttributes());
|
|
||||||
}
|
|
||||||
return call;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::BasicBlock *landingPad = scopes.getLandingPad();
|
|
||||||
|
|
||||||
llvm::BasicBlock *postinvoke = irs.insertBB("postinvoke");
|
|
||||||
llvm::InvokeInst *invoke = irs.ir->CreateInvoke(
|
|
||||||
callee, postinvoke, landingPad, args, BundleList, name);
|
|
||||||
if (calleeFn) {
|
|
||||||
invoke->setAttributes(calleeFn->getAttributes());
|
|
||||||
}
|
|
||||||
|
|
||||||
irs.scope() = IRScope(postinvoke);
|
|
||||||
return invoke;
|
|
||||||
}
|
|
||||||
|
|
|
@ -87,34 +87,35 @@ llvm::BasicBlock *IRState::insertBB(const llvm::Twine &name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, const char *Name) {
|
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, const char *Name) {
|
||||||
LLSmallVector<LLValue *, 1> args;
|
return funcGen().callOrInvoke(Callee, {}, Name);
|
||||||
return funcGen().callOrInvoke(Callee, args, Name);
|
}
|
||||||
|
|
||||||
|
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee,
|
||||||
|
llvm::ArrayRef<LLValue *> Args,
|
||||||
|
const char *Name, bool isNothrow) {
|
||||||
|
return funcGen().callOrInvoke(Callee, Args, Name, isNothrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
||||||
const char *Name) {
|
const char *Name) {
|
||||||
LLValue *args[] = {Arg1};
|
return funcGen().callOrInvoke(Callee, {Arg1}, Name);
|
||||||
return funcGen().callOrInvoke(Callee, args, Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
||||||
LLValue *Arg2, const char *Name) {
|
LLValue *Arg2, const char *Name) {
|
||||||
LLValue *args[] = {Arg1, Arg2};
|
return CreateCallOrInvoke(Callee, {Arg1, Arg2}, Name);
|
||||||
return funcGen().callOrInvoke(Callee, args, Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
||||||
LLValue *Arg2, LLValue *Arg3,
|
LLValue *Arg2, LLValue *Arg3,
|
||||||
const char *Name) {
|
const char *Name) {
|
||||||
LLValue *args[] = {Arg1, Arg2, Arg3};
|
return CreateCallOrInvoke(Callee, {Arg1, Arg2, Arg3}, Name);
|
||||||
return funcGen().callOrInvoke(Callee, args, Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
||||||
LLValue *Arg2, LLValue *Arg3,
|
LLValue *Arg2, LLValue *Arg3,
|
||||||
LLValue *Arg4, const char *Name) {
|
LLValue *Arg4, const char *Name) {
|
||||||
LLValue *args[] = {Arg1, Arg2, Arg3, Arg4};
|
return CreateCallOrInvoke(Callee, {Arg1, Arg2, Arg3, Arg4}, Name);
|
||||||
return funcGen().callOrInvoke(Callee, args, Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRState::isMainFunc(const IrFunction *func) const {
|
bool IRState::isMainFunc(const IrFunction *func) const {
|
||||||
|
|
|
@ -158,6 +158,10 @@ public:
|
||||||
|
|
||||||
// create a call or invoke, depending on the landing pad info
|
// create a call or invoke, depending on the landing pad info
|
||||||
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, const char *Name = "");
|
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, const char *Name = "");
|
||||||
|
llvm::CallSite CreateCallOrInvoke(LLValue *Callee,
|
||||||
|
llvm::ArrayRef<LLValue *> Args,
|
||||||
|
const char *Name = "",
|
||||||
|
bool isNothrow = false);
|
||||||
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
||||||
const char *Name = "");
|
const char *Name = "");
|
||||||
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
||||||
|
|
|
@ -293,7 +293,7 @@ void DtoAssert(Module *M, Loc &loc, DValue *msg) {
|
||||||
args.push_back(DtoConstUint(loc.linnum));
|
args.push_back(DtoConstUint(loc.linnum));
|
||||||
|
|
||||||
// call
|
// call
|
||||||
gIR->funcGen().callOrInvoke(fn, args);
|
gIR->CreateCallOrInvoke(fn, args);
|
||||||
|
|
||||||
// after assert is always unreachable
|
// after assert is always unreachable
|
||||||
gIR->ir->CreateUnreachable();
|
gIR->ir->CreateUnreachable();
|
||||||
|
@ -333,7 +333,7 @@ void DtoCAssert(Module *M, Loc &loc, LLValue *msg) {
|
||||||
args.push_back(line);
|
args.push_back(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
gIR->funcGen().callOrInvoke(fn, args);
|
gIR->CreateCallOrInvoke(fn, args);
|
||||||
|
|
||||||
gIR->ir->CreateUnreachable();
|
gIR->ir->CreateUnreachable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gen/passes/Passes.h"
|
#include "gen/passes/Passes.h"
|
||||||
|
#include "gen/tollvm.h"
|
||||||
#include "gen/runtime.h"
|
#include "gen/runtime.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
|
@ -168,7 +169,7 @@ struct LLVM_LIBRARY_VISIBILITY ArraySetLengthOpt : public LibCallOptimization {
|
||||||
struct LLVM_LIBRARY_VISIBILITY ArrayCastLenOpt : public LibCallOptimization {
|
struct LLVM_LIBRARY_VISIBILITY ArrayCastLenOpt : public LibCallOptimization {
|
||||||
Value *CallOptimizer(Function *Callee, CallInst *CI,
|
Value *CallOptimizer(Function *Callee, CallInst *CI,
|
||||||
IRBuilder<> &B) override {
|
IRBuilder<> &B) override {
|
||||||
// Verify we have a reasonable prototype for _d_array_cast_len
|
// Verify we have a reasonable prototype for _d_arraycast_len
|
||||||
const FunctionType *FT = Callee->getFunctionType();
|
const FunctionType *FT = Callee->getFunctionType();
|
||||||
const llvm::Type *RetTy = FT->getReturnType();
|
const llvm::Type *RetTy = FT->getReturnType();
|
||||||
if (Callee->arg_size() != 3 || !isa<IntegerType>(RetTy) ||
|
if (Callee->arg_size() != 3 || !isa<IntegerType>(RetTy) ||
|
||||||
|
@ -261,27 +262,28 @@ struct LLVM_LIBRARY_VISIBILITY ArraySliceCopyOpt : public LibCallOptimization {
|
||||||
// Verify we have a reasonable prototype for _d_array_slice_copy
|
// Verify we have a reasonable prototype for _d_array_slice_copy
|
||||||
const FunctionType *FT = Callee->getFunctionType();
|
const FunctionType *FT = Callee->getFunctionType();
|
||||||
const llvm::Type *VoidPtrTy = PointerType::getUnqual(B.getInt8Ty());
|
const llvm::Type *VoidPtrTy = PointerType::getUnqual(B.getInt8Ty());
|
||||||
if (Callee->arg_size() != 4 || FT->getReturnType() != B.getVoidTy() ||
|
if (Callee->arg_size() != 5 || FT->getReturnType() != B.getVoidTy() ||
|
||||||
FT->getParamType(0) != VoidPtrTy ||
|
FT->getParamType(0) != VoidPtrTy ||
|
||||||
!isa<IntegerType>(FT->getParamType(1)) ||
|
!isa<IntegerType>(FT->getParamType(1)) ||
|
||||||
FT->getParamType(2) != VoidPtrTy ||
|
FT->getParamType(2) != VoidPtrTy ||
|
||||||
FT->getParamType(3) != FT->getParamType(1)) {
|
FT->getParamType(3) != FT->getParamType(1) ||
|
||||||
|
FT->getParamType(4) != FT->getParamType(1)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value *Size = CI->getOperand(1);
|
Value *DstLength = CI->getOperand(1);
|
||||||
|
|
||||||
// Check the lengths match
|
// Check the lengths match
|
||||||
if (CI->getOperand(3) != Size) {
|
if (CI->getOperand(3) != DstLength) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume unknown size unless we have constant size (that fits in an uint)
|
const auto ElemSz = llvm::cast<ConstantInt>(CI->getOperand(4));
|
||||||
unsigned Sz = ~0U;
|
|
||||||
if (ConstantInt *Int = dyn_cast<ConstantInt>(Size)) {
|
// Assume unknown size unless we have constant length
|
||||||
if (Int->getValue().isIntN(32)) {
|
std::uint64_t Sz = llvm::MemoryLocation::UnknownSize;
|
||||||
Sz = Int->getValue().getZExtValue();
|
if (ConstantInt *Int = dyn_cast<ConstantInt>(DstLength)) {
|
||||||
}
|
Sz = (Int->getValue() * ElemSz->getValue()).getZExtValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the pointers may alias
|
// Check if the pointers may alias
|
||||||
|
@ -291,6 +293,9 @@ struct LLVM_LIBRARY_VISIBILITY ArraySliceCopyOpt : public LibCallOptimization {
|
||||||
|
|
||||||
// Equal length and the pointers definitely don't alias, so it's safe to
|
// Equal length and the pointers definitely don't alias, so it's safe to
|
||||||
// replace the call with memcpy
|
// replace the call with memcpy
|
||||||
|
auto Size = Sz != llvm::MemoryLocation::UnknownSize
|
||||||
|
? DtoConstSize_t(Sz)
|
||||||
|
: B.CreateMul(DstLength, ElemSz);
|
||||||
return EmitMemCpy(CI->getOperand(0), CI->getOperand(2), Size, 1, B);
|
return EmitMemCpy(CI->getOperand(0), CI->getOperand(2), Size, 1, B);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -345,9 +350,9 @@ FunctionPass *createSimplifyDRuntimeCalls() {
|
||||||
/// we know.
|
/// we know.
|
||||||
void SimplifyDRuntimeCalls::InitOptimizations() {
|
void SimplifyDRuntimeCalls::InitOptimizations() {
|
||||||
// Some array-related optimizations
|
// Some array-related optimizations
|
||||||
|
Optimizations["_d_arraycast_len"] = &ArrayCastLen;
|
||||||
Optimizations["_d_arraysetlengthT"] = &ArraySetLength;
|
Optimizations["_d_arraysetlengthT"] = &ArraySetLength;
|
||||||
Optimizations["_d_arraysetlengthiT"] = &ArraySetLength;
|
Optimizations["_d_arraysetlengthiT"] = &ArraySetLength;
|
||||||
Optimizations["_d_array_cast_len"] = &ArrayCastLen;
|
|
||||||
Optimizations["_d_array_slice_copy"] = &ArraySliceCopy;
|
Optimizations["_d_array_slice_copy"] = &ArraySliceCopy;
|
||||||
|
|
||||||
/* Delete calls to runtime functions which aren't needed if their result is
|
/* Delete calls to runtime functions which aren't needed if their result is
|
||||||
|
|
|
@ -69,12 +69,12 @@ static void checkForImplicitGCCall(const Loc &loc, const char *name) {
|
||||||
"_aaValues",
|
"_aaValues",
|
||||||
"_d_allocmemory",
|
"_d_allocmemory",
|
||||||
"_d_allocmemoryT",
|
"_d_allocmemoryT",
|
||||||
"_d_array_cast_len",
|
|
||||||
"_d_array_slice_copy",
|
"_d_array_slice_copy",
|
||||||
"_d_arrayappendT",
|
"_d_arrayappendT",
|
||||||
"_d_arrayappendcTX",
|
"_d_arrayappendcTX",
|
||||||
"_d_arrayappendcd",
|
"_d_arrayappendcd",
|
||||||
"_d_arrayappendwd",
|
"_d_arrayappendwd",
|
||||||
|
"_d_arraycast_len",
|
||||||
"_d_arraycatT",
|
"_d_arraycatT",
|
||||||
"_d_arraycatnTX",
|
"_d_arraycatnTX",
|
||||||
"_d_arraysetlengthT",
|
"_d_arraysetlengthT",
|
||||||
|
@ -650,9 +650,10 @@ static void buildRuntimeModule() {
|
||||||
|
|
||||||
// array slice copy when assertions are on!
|
// array slice copy when assertions are on!
|
||||||
// void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t
|
// void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t
|
||||||
// srclen)
|
// srclen, size_t elemsz)
|
||||||
createFwdDecl(LINKc, voidTy, {"_d_array_slice_copy"},
|
createFwdDecl(LINKc, voidTy, {"_d_array_slice_copy"},
|
||||||
{voidPtrTy, sizeTy, voidPtrTy, sizeTy}, {}, Attr_1_3_NoCapture);
|
{voidPtrTy, sizeTy, voidPtrTy, sizeTy, sizeTy}, {},
|
||||||
|
Attr_1_3_NoCapture);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -691,8 +692,8 @@ static void buildRuntimeModule() {
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// fixes the length for dynamic array casts
|
// fixes the length for dynamic array casts
|
||||||
// size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz)
|
// size_t _d_arraycast_len(size_t len, size_t elemsz, size_t newelemsz)
|
||||||
createFwdDecl(LINKc, sizeTy, {"_d_array_cast_len"}, {sizeTy, sizeTy, sizeTy},
|
createFwdDecl(LINKc, sizeTy, {"_d_arraycast_len"}, {sizeTy, sizeTy, sizeTy},
|
||||||
{}, Attr_ReadNone);
|
{}, Attr_ReadNone);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -886,8 +886,7 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
|
||||||
}
|
}
|
||||||
|
|
||||||
// call the function
|
// call the function
|
||||||
LLCallSite call =
|
LLCallSite call = gIR->CreateCallOrInvoke(callable, args, "", tf->isnothrow);
|
||||||
gIR->funcGen().callOrInvoke(callable, args, "", tf->isnothrow);
|
|
||||||
|
|
||||||
// PGO: Insert instrumentation or attach profile metadata at indirect call
|
// PGO: Insert instrumentation or attach profile metadata at indirect call
|
||||||
// sites.
|
// sites.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1ec2190a1d02de2c043dc8ef6aeab5c0e5e86cdd
|
Subproject commit 424f7ed10f0529b92f76eb843d83d146c117cbed
|
Loading…
Add table
Add a link
Reference in a new issue