diff --git a/dmd2/mars.h b/dmd2/mars.h index 1c641383..dc391ade 100644 --- a/dmd2/mars.h +++ b/dmd2/mars.h @@ -193,13 +193,9 @@ struct Param bool useInvariants; // generate class invariant checks bool useIn; // generate precondition checks bool useOut; // generate postcondition checks -#if IN_LLVM - bool useArrayBounds; -#else char useArrayBounds; // 0: no array bounds checks // 1: array bounds checks for safe functions only // 2: array bounds checks for all functions -#endif bool noboundscheck; // no array bounds checking at all bool stackstomp; // add stack stomping code bool useSwitchError; // check for switches without a default diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp index 61c389bd..8b688953 100644 --- a/driver/cl_options.cpp +++ b/driver/cl_options.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "driver/cl_options.h" +#include "mars.h" #include "gen/cl_helpers.h" #include "gen/logger.h" #include "llvm/Support/CommandLine.h" @@ -221,7 +222,7 @@ struct D_DebugStorage { if (str.empty()) { // Bare "-d-debug" has a special meaning. global.params.useAssert = true; - global.params.useArrayBounds = true; + global.params.useArrayBounds = 2; global.params.useInvariants = true; global.params.useIn = true; global.params.useOut = true; @@ -320,11 +321,8 @@ static cl::opt asserts("asserts", cl::location(global.params.useAssert), cl::init(true)); -static cl::opt boundsChecks("boundscheck", - cl::desc("(*) Enable array bounds checks"), - cl::value_desc("bool"), - cl::location(global.params.useArrayBounds), - cl::init(true)); +cl::opt boundsChecks("boundscheck", + cl::desc("(*) Enable array bounds checks")); static cl::opt invariants("invariants", cl::desc("(*) Enable invariants"), @@ -348,8 +346,9 @@ static cl::opt contracts("contracts", cl::desc("(*) Enable function pre- and post-conditions"), cl::location(ContractsSetter)); +bool nonSafeBoundsChecks = true; static MultiSetter ReleaseSetter(true, &global.params.useAssert, - &global.params.useArrayBounds, &global.params.useInvariants, + &nonSafeBoundsChecks, &global.params.useInvariants, &global.params.useOut, &global.params.useIn, NULL); static cl::opt > release("release", cl::desc("Disables asserts, invariants, contracts and boundscheck"), diff --git a/driver/cl_options.h b/driver/cl_options.h index d1320894..25afb5a6 100644 --- a/driver/cl_options.h +++ b/driver/cl_options.h @@ -15,7 +15,7 @@ #ifndef LDC_DRIVER_CL_OPTIONS_H #define LDC_DRIVER_CL_OPTIONS_H -#include "mars.h" +#include "gen/cl_helpers.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/CommandLine.h" #include @@ -63,6 +63,9 @@ namespace opts { extern cl::opt singleObj; extern cl::opt linkonceTemplates; + extern cl::opt boundsChecks; + extern bool nonSafeBoundsChecks; + // Arguments to -d-debug extern std::vector debugArgs; // Arguments to -run diff --git a/driver/main.cpp b/driver/main.cpp index b9f6a207..ddc06278 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -175,6 +175,7 @@ int main(int argc, char** argv) global.params.argv0 = argv[0]; #endif global.params.useSwitchError = 1; + global.params.useArrayBounds = 2; global.params.linkswitches = new Strings(); global.params.libfiles = new Strings(); @@ -369,6 +370,14 @@ int main(int argc, char** argv) if (global.params.useUnitTests) global.params.useAssert = 1; + // Bounds checking is a bit peculiar: -enable/disable-boundscheck is an + // absolute decision. Only if no explicit option is specified, -release + // downgrades useArrayBounds 2 to 1 (only for safe functions). + if (opts::boundsChecks == cl::BOU_UNSET) + global.params.useArrayBounds = opts::nonSafeBoundsChecks ? 2 : 1; + else + global.params.useArrayBounds = (opts::boundsChecks == cl::BOU_TRUE) ? 2 : 0; + // LDC output determination // if we don't link, autodetect target from extension diff --git a/gen/aa.cpp b/gen/aa.cpp index 9ab363a2..bbebda5d 100644 --- a/gen/aa.cpp +++ b/gen/aa.cpp @@ -80,7 +80,7 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue) // Only check bounds for rvalues ('aa[key]'). // Lvalue use ('aa[key] = value') auto-adds an element. - if (!lvalue && global.params.useArrayBounds) { + if (!lvalue && gIR->emitArrayBoundsChecks()) { llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* failbb = llvm::BasicBlock::Create(gIR->context(), "aaboundscheckfail", gIR->topfunc(), oldend); llvm::BasicBlock* okbb = llvm::BasicBlock::Create(gIR->context(), "aaboundsok", gIR->topfunc(), oldend); diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 278aa762..36c0c519 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -385,7 +385,7 @@ static LLValue* get_slice_ptr(DSliceValue* e, LLValue*& sz) static void copySlice(LLValue* dstarr, LLValue* sz1, LLValue* srcarr, LLValue* sz2) { - if (global.params.useAssert || global.params.useArrayBounds) + if (global.params.useAssert || gIR->emitArrayBoundsChecks()) { LLValue* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_array_slice_copy"); gIR->CreateCallOrInvoke4(fn, dstarr, sz1, srcarr, sz2); diff --git a/gen/irstate.cpp b/gen/irstate.cpp index e260b763..be6f1840 100644 --- a/gen/irstate.cpp +++ b/gen/irstate.cpp @@ -165,6 +165,21 @@ LLCallSite IRState::CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* return CreateCallOrInvoke(Callee, args, Name); } +bool IRState::emitArrayBoundsChecks() +{ + int p = global.params.useArrayBounds; + + // 0 or 2 are absolute decisions. + if (p != 1) return p != 0; + + // Safe functions only. + if (functions.empty()) return false; + + Type* t = func()->decl->type; + return t->ty == Tfunction && ((TypeFunction*)t)->trust == TRUSTsafe; +} + + ////////////////////////////////////////////////////////////////////////////////////////// IRBuilder<>* IRBuilderHelper::operator->() diff --git a/gen/irstate.h b/gen/irstate.h index 3d57918e..45659988 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -208,6 +208,9 @@ struct IRState // 'used' array solely for keeping a reference to globals std::vector usedArray; + + /// Whether to emit array bounds checking in the current function. + bool emitArrayBoundsChecks(); }; template diff --git a/gen/toir.cpp b/gen/toir.cpp index b6238238..d1ee19fe 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1609,12 +1609,12 @@ DValue* IndexExp::toElem(IRState* p) arrptr = DtoGEP1(l->getRVal(),r->getRVal()); } else if (e1type->ty == Tsarray) { - if(global.params.useArrayBounds) + if (gIR->emitArrayBoundsChecks()) DtoArrayBoundsCheck(loc, l, r); arrptr = DtoGEP(l->getRVal(), zero, r->getRVal()); } else if (e1type->ty == Tarray) { - if(global.params.useArrayBounds) + if (gIR->emitArrayBoundsChecks()) DtoArrayBoundsCheck(loc, l, r); arrptr = DtoArrayPtr(l); arrptr = DtoGEP1(arrptr,r->getRVal()); @@ -1672,7 +1672,7 @@ DValue* SliceExp::toElem(IRState* p) LLValue* vlo = lo->getRVal(); LLValue* vup = up->getRVal(); - if(global.params.useArrayBounds) + if (gIR->emitArrayBoundsChecks()) DtoArrayBoundsCheck(loc, e, up, lo); // offset by lower