From 7882f4858e223eccc28f561fc28f8115087594f7 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Wed, 30 Jul 2008 18:38:56 +0200 Subject: [PATCH] Enable array bounds check and emit them in IndexExp. --- dmd/mars.c | 2 +- gen/llvmhelpers.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++++ gen/llvmhelpers.h | 2 ++ gen/toir.cpp | 4 +++ 4 files changed, 82 insertions(+), 1 deletion(-) diff --git a/dmd/mars.c b/dmd/mars.c index 267b0c9d..760a19b4 100644 --- a/dmd/mars.c +++ b/dmd/mars.c @@ -270,7 +270,7 @@ int main(int argc, char *argv[]) global.params.useInvariants = 1; global.params.useIn = 1; global.params.useOut = 1; - global.params.useArrayBounds = 0; + global.params.useArrayBounds = 1; global.params.useSwitchError = 1; global.params.useInline = 0; // this one messes things up to a point where codegen breaks global.params.llvmInline = 0; // use this one instead to know if inline passes should be run diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 334bde94..4425eda7 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -153,6 +153,81 @@ void DtoAssert(Loc* loc, DValue* msg) gIR->ir->CreateUnreachable(); } +/****************************************************************************************/ +/*//////////////////////////////////////////////////////////////////////////////////////// +// ARRAY BOUNDS HELPER +////////////////////////////////////////////////////////////////////////////////////////*/ + +void DtoArrayBoundsCheck(Loc& loc, DValue* arr, DValue* index) +{ + Type* arrty = arr->getType(); + assert((arrty->ty == Tsarray || arrty->ty == Tarray) && "Can only array bounds check for static or dynamic arrays"); + + // static arrays can get static checks for static indices + + if(arr->getType()->ty == Tsarray) + { + TypeSArray* tsa = (TypeSArray*)arrty; + size_t tdim = tsa->dim->toInteger(); + + if(llvm::ConstantInt* cindex = llvm::dyn_cast(index->getRVal())) + if(cindex->uge(tdim)) { + error(loc, "index %d is larger than array size %d", index, tdim); + return; + } + } + + // runtime check + + llvm::BasicBlock* oldend = gIR->scopeend(); + llvm::BasicBlock* failbb = llvm::BasicBlock::Create("arrayboundscheckfail", gIR->topfunc(), oldend); + llvm::BasicBlock* okbb = llvm::BasicBlock::Create("arrayboundsok", gIR->topfunc(), oldend); + + LLValue* cond = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_ULT, index->getRVal(), DtoArrayLen(arr), "boundscheck"); + gIR->ir->CreateCondBr(cond, okbb, failbb); + + // set up failbb to call the array bounds error runtime function + + gIR->scope() = IRScope(failbb, okbb); + + std::vector args; + llvm::PAListPtr palist; + + // file param + // FIXME: every array bounds check creates a global for the filename !!! + LLConstant* c = DtoConstString(loc.filename); + + llvm::AllocaInst* alloc = gIR->func()->srcfileArg; + if (!alloc) + { + alloc = new llvm::AllocaInst(c->getType(), ".srcfile", gIR->topallocapoint()); + gIR->func()->srcfileArg = alloc; + } + LLValue* ptr = DtoGEPi(alloc, 0,0, "tmp"); + DtoStore(c->getOperand(0), ptr); + ptr = DtoGEPi(alloc, 0,1, "tmp"); + DtoStore(c->getOperand(1), ptr); + + args.push_back(alloc); + palist = palist.addAttr(1, llvm::ParamAttr::ByVal); + + // line param + c = DtoConstUint(loc.linnum); + args.push_back(c); + + // call + llvm::Function* errorfn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_array_bounds"); + CallOrInvoke* call = gIR->CreateCallOrInvoke(errorfn, args.begin(), args.end()); + call->setParamAttrs(palist); + + // the function does not return + gIR->ir->CreateUnreachable(); + + + // if ok, proceed in okbb + gIR->scope() = IRScope(okbb, oldend); +} + /****************************************************************************************/ /*//////////////////////////////////////////////////////////////////////////////////////// // LABEL HELPER diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 7b584863..19beb97c 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -13,6 +13,8 @@ void DtoDeleteArray(DValue* arr); // assertion generator void DtoAssert(Loc* loc, DValue* msg); +// array boundary check generator +void DtoArrayBoundsCheck(Loc& loc, DValue* arr, DValue* index); // return the LabelStatement from the current function with the given identifier or NULL if not found LabelStatement* DtoLabelStatement(Identifier* ident); diff --git a/gen/toir.cpp b/gen/toir.cpp index 6b95cd01..5639251f 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1008,9 +1008,13 @@ DValue* IndexExp::toElem(IRState* p) arrptr = DtoGEP1(l->getRVal(),r->getRVal()); } else if (e1type->ty == Tsarray) { + if(global.params.useArrayBounds) + DtoArrayBoundsCheck(loc, l, r); arrptr = DtoGEP(l->getRVal(), zero, r->getRVal()); } else if (e1type->ty == Tarray) { + if(global.params.useArrayBounds) + DtoArrayBoundsCheck(loc, l, r); arrptr = DtoArrayPtr(l); arrptr = DtoGEP1(arrptr,r->getRVal()); }