changeset 439:47b64d06eb9f

Enable array bounds check and emit them in IndexExp.
author Christian Kamm <kamm incasoftware de>
date Wed, 30 Jul 2008 18:38:56 +0200
parents 3c133dd1eda3
children d8dc221d3db7
files dmd/mars.c gen/llvmhelpers.cpp gen/llvmhelpers.h gen/toir.cpp
diffstat 4 files changed, 82 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/mars.c	Wed Jul 30 16:48:35 2008 +0200
+++ b/dmd/mars.c	Wed Jul 30 18:38:56 2008 +0200
@@ -270,7 +270,7 @@
     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
--- a/gen/llvmhelpers.cpp	Wed Jul 30 16:48:35 2008 +0200
+++ b/gen/llvmhelpers.cpp	Wed Jul 30 18:38:56 2008 +0200
@@ -155,6 +155,81 @@
 
 /****************************************************************************************/
 /*////////////////////////////////////////////////////////////////////////////////////////
+// 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<llvm::ConstantInt>(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<LLValue*> 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
 ////////////////////////////////////////////////////////////////////////////////////////*/
 LabelStatement* DtoLabelStatement(Identifier* ident)
--- a/gen/llvmhelpers.h	Wed Jul 30 16:48:35 2008 +0200
+++ b/gen/llvmhelpers.h	Wed Jul 30 18:38:56 2008 +0200
@@ -13,6 +13,8 @@
 
 // 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);
--- a/gen/toir.cpp	Wed Jul 30 16:48:35 2008 +0200
+++ b/gen/toir.cpp	Wed Jul 30 18:38:56 2008 +0200
@@ -1008,9 +1008,13 @@
         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());
     }