diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp index d230bc0f12..8592184411 100644 --- a/driver/cl_options.cpp +++ b/driver/cl_options.cpp @@ -721,6 +721,11 @@ cl::opt cl::desc("Warn for stack size bigger than the given number"), cl::value_desc("threshold")); +cl::opt + enableGetElementPtrNuw("enable-getelementptr-nuw", cl::ZeroOrMore, + cl::desc("enable nuw(no-unsigned-wrap) flag to " + "LLVM's getelementptr insturction")); + #if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX cl::list dcomputeTargets("mdcompute-targets", cl::CommaSeparated, diff --git a/driver/cl_options.h b/driver/cl_options.h index 01596ccc8e..0d8a2f526d 100644 --- a/driver/cl_options.h +++ b/driver/cl_options.h @@ -138,6 +138,8 @@ extern cl::opt saveOptimizationRecord; extern cl::opt fWarnStackSize; +extern cl::opt enableGetElementPtrNuw; + #if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX extern cl::list dcomputeTargets; extern cl::opt dcomputeFilePrefix; diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 198bb23ed7..e39cb321b7 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -17,6 +17,7 @@ #include "dmd/init.h" #include "dmd/module.h" #include "dmd/template.h" +#include "driver/cl_options.h" #include "gen/abi/abi.h" #include "gen/arrays.h" #include "gen/classes.h" @@ -1868,9 +1869,18 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad, LLValue *ptr = src; LLType * ty = nullptr; +#if LDC_LLVM_VER >= 2000 + llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds(); + if (opts::enableGetElementPtrNuw) + nw |= llvm::GEPNoWrapFlags::noUnsignedWrap(); +#endif if (!isFieldIdx) { // apply byte-wise offset from object start - ptr = DtoGEP1(getI8Type(), ptr, off); + ptr = DtoGEP1(getI8Type(), ptr, off +#if LDC_LLVM_VER >= 2000 + , "", nullptr, nw +#endif + ); ty = DtoType(vd->type); } else { if (ad->structsize == 0) { // can happen for extern(C) structs @@ -1884,7 +1894,11 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad, } else { st = irTypeAggr->getLLType(); } - ptr = DtoGEP(st, ptr, 0, off); + ptr = DtoGEP(st, ptr, 0, off +#if LDC_LLVM_VER >= 2000 + , "", nullptr, nw +#endif + ); ty = isaStruct(st)->getElementType(off); } } diff --git a/gen/toir.cpp b/gen/toir.cpp index 8ac304b25c..975a61bdf4 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -22,6 +22,7 @@ #include "dmd/root/rmem.h" #include "dmd/target.h" #include "dmd/template.h" +#include "driver/cl_options.h" #include "gen/aa.h" #include "gen/abi/abi.h" #include "gen/arrays.h" @@ -1198,7 +1199,16 @@ class ToElemVisitor : public Visitor { } LLType *elt = DtoMemType(e1type->nextOf()); LLType *arrty = llvm::ArrayType::get(elt, e1type->isTypeSArray()->dim->isIntegerExp()->getInteger()); - arrptr = DtoGEP(arrty, DtoLVal(l), DtoConstUint(0), DtoRVal(r)); +#if LDC_LLVM_VER >= 2000 + llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds(); + if (e->indexIsInBounds && opts::enableGetElementPtrNuw) + nw |= llvm::GEPNoWrapFlags::noUnsignedWrap(); +#endif + arrptr = DtoGEP(arrty, DtoLVal(l), DtoConstUint(0), DtoRVal(r) +#if LDC_LLVM_VER >= 2000 + , "", nullptr, nw +#endif + ); } else if (e1type->ty == TY::Tarray) { if (p->emitArrayBoundsChecks() && !e->indexIsInBounds) { DtoIndexBoundsCheck(e->loc, l, r); @@ -1292,8 +1302,16 @@ class ToElemVisitor : public Visitor { } // offset by lower - eptr = DtoGEP1(DtoMemType(etype->nextOf()), getBasePointer(), vlo, "lowerbound"); - +#if LDC_LLVM_VER >= 2000 + llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds(); + if (!needCheckUpper && !needCheckLower && opts::enableGetElementPtrNuw) + nw |= llvm::GEPNoWrapFlags::noUnsignedWrap(); +#endif + eptr = DtoGEP1(DtoMemType(etype->nextOf()), getBasePointer(), vlo, "lowerbound" +#if LDC_LLVM_VER >= 2000 + , nullptr, nw +#endif + ); // adjust length elen = p->ir->CreateSub(vup, vlo); } diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 63465ed887..fd5a5f9109 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -357,46 +357,103 @@ LLIntegerType *DtoSize_t() { namespace { llvm::GetElementPtrInst *DtoGEP(LLType *pointeeTy, LLValue *ptr, llvm::ArrayRef indices, - const char *name, llvm::BasicBlock *bb) { + const char *name, llvm::BasicBlock *bb +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw +#endif + ) { auto gep = llvm::GetElementPtrInst::Create(pointeeTy, ptr, indices, name, bb ? bb : gIR->scopebb()); +#if LDC_LLVM_VER >= 2000 + gep->setNoWrapFlags(nw); +#else gep->setIsInBounds(true); +#endif return gep; } } LLValue *DtoGEP1(LLType *pointeeTy, LLValue *ptr, LLValue *i0, const char *name, - llvm::BasicBlock *bb) { - return DtoGEP(pointeeTy, ptr, i0, name, bb); + llvm::BasicBlock *bb +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw +#endif + ) { + return DtoGEP(pointeeTy, ptr, i0, name, bb +#if LDC_LLVM_VER >= 2000 + , nw +#endif + ); } LLValue *DtoGEP(LLType *pointeeTy, LLValue *ptr, LLValue *i0, LLValue *i1, - const char *name, llvm::BasicBlock *bb) { + const char *name, llvm::BasicBlock *bb +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw +#endif + ) { LLValue *indices[] = {i0, i1}; - return DtoGEP(pointeeTy, ptr, indices, name, bb); + return DtoGEP(pointeeTy, ptr, indices, name, bb +#if LDC_LLVM_VER >= 2000 + , nw +#endif + ); } LLValue *DtoGEP1(LLType *pointeeTy, LLValue *ptr, unsigned i0, const char *name, - llvm::BasicBlock *bb) { - return DtoGEP(pointeeTy, ptr, DtoConstUint(i0), name, bb); + llvm::BasicBlock *bb +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw +#endif + ) { + return DtoGEP(pointeeTy, ptr, DtoConstUint(i0), name, bb +#if LDC_LLVM_VER >= 2000 + , nw +#endif + ); } LLValue *DtoGEP(LLType *pointeeTy, LLValue *ptr, unsigned i0, unsigned i1, - const char *name, llvm::BasicBlock *bb) { + const char *name, llvm::BasicBlock *bb +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw +#endif + ) { LLValue *indices[] = {DtoConstUint(i0), DtoConstUint(i1)}; - return DtoGEP(pointeeTy, ptr, indices, name, bb); + return DtoGEP(pointeeTy, ptr, indices, name, bb +#if LDC_LLVM_VER >= 2000 + , nw +#endif + ); } LLConstant *DtoGEP(LLType *pointeeTy, LLConstant *ptr, unsigned i0, - unsigned i1) { + unsigned i1 +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw +#endif + ) { LLValue *indices[] = {DtoConstUint(i0), DtoConstUint(i1)}; return llvm::ConstantExpr::getGetElementPtr(pointeeTy, ptr, indices, - /* InBounds = */ true); +#if LDC_LLVM_VER >= 2000 + nw +#else + /* InBounds = */ true +#endif + ); } LLValue *DtoGEP1i64(LLType *pointeeTy, LLValue *ptr, uint64_t i0, const char *name, - llvm::BasicBlock *bb) { - return DtoGEP(pointeeTy, ptr, DtoConstUlong(i0), name, bb); + llvm::BasicBlock *bb +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw +#endif + ) { + return DtoGEP(pointeeTy, ptr, DtoConstUlong(i0), name, bb +#if LDC_LLVM_VER >= 2000 + , nw +#endif + ); } //////////////////////////////////////////////////////////////////////////////// @@ -701,7 +758,7 @@ LLGlobalVariable *makeGlobal(LLStringRef name, LLType* type, LLStringRef section if (!section.empty()) var->setSection(section); - + return var; } @@ -737,7 +794,7 @@ LLGlobalVariable *makeGlobalWithBytes(LLStringRef name, LLConstantList packedCon 0u, externInit ); - + return var; } diff --git a/gen/tollvm.h b/gen/tollvm.h index 14d22d38d4..373c91f844 100644 --- a/gen/tollvm.h +++ b/gen/tollvm.h @@ -77,19 +77,43 @@ LLStructType *DtoModuleReferenceType(); // getelementptr helpers LLValue *DtoGEP1(LLType *pointeeTy, LLValue *ptr, LLValue *i0, - const char *name = "", llvm::BasicBlock *bb = nullptr); + const char *name = "", llvm::BasicBlock *bb = nullptr +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds() +#endif + ); LLValue *DtoGEP(LLType *pointeeTy, LLValue *ptr, LLValue *i0, LLValue *i1, - const char *name = "", llvm::BasicBlock *bb = nullptr); + const char *name = "", llvm::BasicBlock *bb = nullptr +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds() +#endif + ); LLValue *DtoGEP1(LLType *pointeeTy, LLValue *ptr, unsigned i0, - const char *name = "", llvm::BasicBlock *bb = nullptr); + const char *name = "", llvm::BasicBlock *bb = nullptr +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds() +#endif + ); LLValue *DtoGEP(LLType *pointeeTy, LLValue *ptr, unsigned i0, unsigned i1, - const char *name = "", llvm::BasicBlock *bb = nullptr); + const char *name = "", llvm::BasicBlock *bb = nullptr +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds() +#endif + ); LLConstant *DtoGEP(LLType *pointeeTy, LLConstant *ptr, unsigned i0, - unsigned i1); + unsigned i1 +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds() +#endif + ); LLValue *DtoGEP1i64(LLType *pointeeTy, LLValue *ptr, uint64_t i0, - const char *name = "", llvm::BasicBlock *bb = nullptr); + const char *name = "", llvm::BasicBlock *bb = nullptr +#if LDC_LLVM_VER >= 2000 + , llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds() +#endif + ); // to constant helpers LLConstantInt *DtoConstSize_t(uint64_t); diff --git a/tests/codegen/inbounds.d b/tests/codegen/inbounds.d index d50939f71b..3683448735 100644 --- a/tests/codegen/inbounds.d +++ b/tests/codegen/inbounds.d @@ -1,4 +1,4 @@ -// RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll +// RUN: %ldc -enable-getelementptr-nuw -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll struct S { float x, y; @@ -9,7 +9,7 @@ extern(C): // Avoid name mangling // IndexExp in static array with const exp // CHECK-LABEL: @foo1 int foo1(int[3] a) { - // CHECK: getelementptr inbounds [3 x i32] + // CHECK: getelementptr inbounds{{( nuw)?}} [3 x i32] return a[1]; } @@ -58,7 +58,7 @@ int foo7(int* p, int i) { // Struct field // CHECK-LABEL: @foo8 float foo8(S s) { - // CHECK: getelementptr inbounds + // CHECK: getelementptr inbounds{{( nuw)?}} return s.y; } @@ -79,7 +79,7 @@ int foo10(int[] a, int i) { // SliceExp for static array with const lower bound // CHECK-LABEL: @foo11 int[] foo11(ref int[3] a) { - // CHECK: getelementptr inbounds i32, ptr + // CHECK: getelementptr inbounds{{( nuw)?}} i32, ptr return a[1 .. $]; }