From f5e276d6a666c0eeb0a525dd4576dea27a5b2d22 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 10 Jun 2013 19:09:53 +0200 Subject: [PATCH] Revert meaning of AddExp/MinExp for pointers to DMD default. It might be worth considering to move the stride multiplication down to the glue layer in the upstream sources. But assigning a different meaning to AST nodes was a giant maintenance liability, especially with regard to CTFE. --- dmd2/cast.c | 5 -- dmd2/ctfeexpr.c | 7 --- dmd2/mtype.c | 8 --- gen/toir.cpp | 143 +++++++++++++++++++++++++++++++++++------------- 4 files changed, 106 insertions(+), 57 deletions(-) diff --git a/dmd2/cast.c b/dmd2/cast.c index bba7250d..a055e4ad 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -2005,10 +2005,7 @@ Expression *BinExp::scaleFactor(Scope *sc) stride = t1b->nextOf()->size(loc); if (!t->equals(t2b)) e2 = e2->castTo(sc, t); -// LDC: llvm uses typesafe pointer arithmetic -#if !IN_LLVM e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t)); -#endif eoff = e2; e2->type = t; type = e1->type; @@ -2024,9 +2021,7 @@ Expression *BinExp::scaleFactor(Scope *sc) e = e1->castTo(sc, t); else e = e1; -#if !IN_LLVM e = new MulExp(loc, e, new IntegerExp(0, stride, t)); -#endif eoff = e; e->type = t; type = e2->type; diff --git a/dmd2/ctfeexpr.c b/dmd2/ctfeexpr.c index e56a35da..e01b049b 100644 --- a/dmd2/ctfeexpr.c +++ b/dmd2/ctfeexpr.c @@ -670,17 +670,10 @@ Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type, Expression *val = agg1; TypeArray *tar = (TypeArray *)val->type; sinteger_t indx = ofs1; -#if IN_LLVM // LDC: llvm uses typesafe pointer arithmetic - if (op == TOKadd || op == TOKaddass || op == TOKplusplus) - indx += ofs2; - else if (op == TOKmin || op == TOKminass || op == TOKminusminus) - indx -= ofs2; -#else if (op == TOKadd || op == TOKaddass || op == TOKplusplus) indx = indx + ofs2/sz; else if (op == TOKmin || op == TOKminass || op == TOKminusminus) indx -= ofs2/sz; -#endif else { error(loc, "CTFE Internal compiler error: bad pointer operation"); diff --git a/dmd2/mtype.c b/dmd2/mtype.c index 4fb13713..526b6581 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -8973,17 +8973,9 @@ L1: { /* The handle to the monitor (call it a void*) * *(cast(void**)e + 1) */ -#if IN_LLVM - e = e->castTo(sc, tint8->pointerTo()->pointerTo()); - e = new AddExp(e->loc, e, new IntegerExp(1)); - e->type = tint8->pointerTo(); - e = e->castTo(sc, tvoidptr->pointerTo()); - e = new PtrExp(e->loc, e); -#else e = e->castTo(sc, tvoidptr->pointerTo()); e = new AddExp(e->loc, e, new IntegerExp(1)); e = new PtrExp(e->loc, e); -#endif e = e->semantic(sc); return e; } diff --git a/gen/toir.cpp b/gen/toir.cpp index 360c9d10..5e61007e 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -682,14 +682,24 @@ static void errorOnIllegalArrayOp(Expression* base, Expression* e1, Expression* ////////////////////////////////////////////////////////////////////////////////////////// +static dinteger_t undoStrideMul(const Loc& loc, Type* t, dinteger_t offset) +{ + assert(t->ty == Tpointer); + d_uns64 elemSize = t->nextOf()->size(loc); + assert((offset % elemSize) == 0 && + "Expected offset by an integer amount of elements"); + + return offset / elemSize; +} + LLConstant* AddExp::toConstElem(IRState* p) { // add to pointer - if (e1->type->ty == Tpointer && e2->type->isintegral()) { - LLConstant *ptr = e1->toConstElem(p); - LLConstant *index = e2->toConstElem(p); - ptr = llvm::ConstantExpr::getGetElementPtr(ptr, llvm::makeArrayRef(&index, 1)); - return ptr; + Type* t1b = e1->type->toBasetype(); + if (t1b->ty == Tpointer && e2->type->isintegral()) { + llvm::Constant* ptr = e1->toConstElem(p); + dinteger_t idx = undoStrideMul(loc, t1b, e2->toInteger()); + return llvm::ConstantExpr::getGetElementPtr(ptr, DtoConstSize_t(idx)); } error("expression '%s' is not a constant", toChars()); @@ -697,7 +707,77 @@ LLConstant* AddExp::toConstElem(IRState* p) return NULL; } -////////////////////////////////////////////////////////////////////////////////////////// +/// Tries to remove a MulExp by a constant value of baseSize from e. Returns +/// NULL if not possible. +static Expression* extractNoStrideInc(Expression* e, d_uns64 baseSize, bool& negate) +{ + MulExp* mul; + while (true) + { + if (e->op == TOKneg) + { + negate = !negate; + e = static_cast(e)->e1; + continue; + } + + if (e->op == TOKmul) + { + mul = static_cast(e); + break; + } + + return NULL; + } + + if (!mul->e2->isConst()) return NULL; + dinteger_t stride = mul->e2->toInteger(); + + if (stride != baseSize) return NULL; + + return mul->e1; +} + +static DValue* emitPointerOffset(IRState* p, Loc loc, DValue* base, + Expression* offset, bool negateOffset, Type* resultType) +{ + // The operand emitted by the frontend is in units of bytes, and not + // pointer elements. We try to undo this before resorting to + // temporarily bitcasting the pointer to i8. + + llvm::Value* noStrideInc = NULL; + if (offset->isConst()) + { + dinteger_t byteOffset = offset->toInteger(); + if (byteOffset == 0) + { + Logger::println("offset is zero"); + return base; + } + noStrideInc = DtoConstSize_t(undoStrideMul(loc, base->type, byteOffset)); + } + else if (Expression* inc = extractNoStrideInc(offset, + base->type->nextOf()->size(loc), negateOffset)) + { + noStrideInc = inc->toElem(p)->getRVal(); + } + + if (noStrideInc) + { + if (negateOffset) noStrideInc = p->ir->CreateNeg(noStrideInc); + return new DImValue(base->type, + DtoGEP1(base->getRVal(), noStrideInc, 0, p->scopebb())); + } + + // This might not actually be generated by the frontend, just to be + // safe. + llvm::Value* inc = offset->toElem(p)->getRVal(); + if (negateOffset) inc = p->ir->CreateNeg(inc); + llvm::Value* bytePtr = DtoBitCast(base->getRVal(), getVoidPtrType()); + DValue* result = new DImValue(Type::tvoidptr, DtoGEP1(bytePtr, inc)); + return DtoCast(loc, result, resultType); +} + DValue* AddExp::toElem(IRState* p) { @@ -705,7 +785,6 @@ DValue* AddExp::toElem(IRState* p) LOG_SCOPE; DValue* l = e1->toElem(p); - DValue* r = e2->toElem(p); Type* t = type->toBasetype(); Type* e1type = e1->type->toBasetype(); @@ -713,35 +792,28 @@ DValue* AddExp::toElem(IRState* p) errorOnIllegalArrayOp(this, e1, e2); - if (e1type != e2type && e1type->ty == Tpointer) { - Logger::println("add to pointer"); - if (DConstValue* cv = r->isConst()) { - if (cv->c->isNullValue()) { - Logger::println("is zero"); - return new DImValue(type, l->getRVal()); - } - } - LLValue* v = llvm::GetElementPtrInst::Create(l->getRVal(), r->getRVal(), "tmp", p->scopebb()); - return new DImValue(type, v); + if (e1type != e2type && e1type->ty == Tpointer && e2type->isintegral()) + { + Logger::println("Adding integer to pointer"); + return emitPointerOffset(p, loc, l, e2, false, type); } else if (t->iscomplex()) { - return DtoComplexAdd(loc, type, l, r); + return DtoComplexAdd(loc, type, l, e2->toElem(p)); } else { - return DtoBinAdd(l,r); + return DtoBinAdd(l, e2->toElem(p)); } } -////////////////////////////////////////////////////////////////////////////////////////// - LLConstant* MinExp::toConstElem(IRState* p) { - if (e1->type->ty == Tpointer && e2->type->isintegral()) { - LLConstant *ptr = e1->toConstElem(p); - LLConstant *index = e2->toConstElem(p); - index = llvm::ConstantExpr::getNeg(index); - ptr = llvm::ConstantExpr::getGetElementPtr(ptr, llvm::makeArrayRef(&index, 1)); - return ptr; + Type* t1b = e1->type->toBasetype(); + if (t1b->ty == Tpointer && e2->type->isintegral()) { + llvm::Constant* ptr = e1->toConstElem(p); + dinteger_t idx = undoStrideMul(loc, t1b, e2->toInteger()); + + llvm::Constant* negIdx = llvm::ConstantExpr::getNeg(DtoConstSize_t(idx)); + return llvm::ConstantExpr::getGetElementPtr(ptr, negIdx); } error("expression '%s' is not a constant", toChars()); @@ -749,15 +821,12 @@ LLConstant* MinExp::toConstElem(IRState* p) return NULL; } -////////////////////////////////////////////////////////////////////////////////////////// - DValue* MinExp::toElem(IRState* p) { Logger::print("MinExp::toElem: %s @ %s\n", toChars(), type->toChars()); LOG_SCOPE; DValue* l = e1->toElem(p); - DValue* r = e2->toElem(p); Type* t = type->toBasetype(); Type* t1 = e1->type->toBasetype(); @@ -767,7 +836,7 @@ DValue* MinExp::toElem(IRState* p) if (t1->ty == Tpointer && t2->ty == Tpointer) { LLValue* lv = l->getRVal(); - LLValue* rv = r->getRVal(); + LLValue* rv = e2->toElem(p)->getRVal(); if (Logger::enabled()) Logger::cout() << "lv: " << *lv << " rv: " << *rv << '\n'; lv = p->ir->CreatePtrToInt(lv, DtoSize_t(), "tmp"); @@ -777,16 +846,16 @@ DValue* MinExp::toElem(IRState* p) diff = p->ir->CreateIntToPtr(diff, DtoType(type), "tmp"); return new DImValue(type, diff); } - else if (t1->ty == Tpointer) { - LLValue* idx = p->ir->CreateNeg(r->getRVal(), "tmp"); - LLValue* v = llvm::GetElementPtrInst::Create(l->getRVal(), idx, "tmp", p->scopebb()); - return new DImValue(type, v); + else if (t1->ty == Tpointer && t2->isintegral()) + { + Logger::println("Subtracting integer from pointer"); + return emitPointerOffset(p, loc, l, e2, true, type); } else if (t->iscomplex()) { - return DtoComplexSub(loc, type, l, r); + return DtoComplexSub(loc, type, l, e2->toElem(p)); } else { - return DtoBinSub(l,r); + return DtoBinSub(l, e2->toElem(p)); } }