From 330712fb0150035b436ea6603e6f5c98723352ce Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Mon, 19 May 2025 06:07:50 +0900 Subject: [PATCH 1/8] Emit getelementptr nuw for p++ --- gen/toir.cpp | 7 ++++ gen/tollvm.cpp | 74 +++++++++++++++++++++++++++++++++------- gen/tollvm.h | 30 +++++++++++++--- tests/codegen/inbounds.d | 2 +- 4 files changed, 94 insertions(+), 19 deletions(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index 8ac304b25c4..e7105b51bd7 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1530,7 +1530,14 @@ class ToElemVisitor : public Visitor { assert(e->e2->op == EXP::int64); LLConstant *offset = e->op == EXP::plusPlus ? DtoConstUint(1) : DtoConstInt(-1); +#if LDC_LLVM_VER >= 2000 + auto nw = llvm::GEPNoWrapFlags::inBounds(); + if (e->op == EXP::plusPlus) + nw |= llvm::GEPNoWrapFlags::noUnsignedWrap(); + post = DtoGEP1(DtoMemType(dv->type->nextOf()), val, offset, "", p->scopebb(), nw); +#else post = DtoGEP1(DtoMemType(dv->type->nextOf()), val, offset, "", p->scopebb()); +#endif } else if (e1type->isComplex()) { assert(e2type->isComplex()); LLValue *one = LLConstantFP::get(DtoComplexBaseType(e1type), 1.0); diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 63465ed887a..c1fac2b98a4 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -357,34 +357,74 @@ 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, @@ -395,8 +435,16 @@ LLConstant *DtoGEP(LLType *pointeeTy, LLConstant *ptr, unsigned i0, } 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 +749,7 @@ LLGlobalVariable *makeGlobal(LLStringRef name, LLType* type, LLStringRef section if (!section.empty()) var->setSection(section); - + return var; } @@ -737,7 +785,7 @@ LLGlobalVariable *makeGlobalWithBytes(LLStringRef name, LLConstantList packedCon 0u, externInit ); - + return var; } diff --git a/gen/tollvm.h b/gen/tollvm.h index 14d22d38d4e..291c9209801 100644 --- a/gen/tollvm.h +++ b/gen/tollvm.h @@ -77,19 +77,39 @@ 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); 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 d50939f71b9..b331cde5676 100644 --- a/tests/codegen/inbounds.d +++ b/tests/codegen/inbounds.d @@ -30,7 +30,7 @@ int foo3(int* p, int i) { // PostExp in pointer // CHECK-LABEL: @foo4 int foo4(int* p) { - // CHECK: getelementptr inbounds + // CHECK: getelementptr inbounds{{( nuw)?}} return *p++; } From ad730d34d387bee660f867d06774207ab9e56b7a Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Mon, 19 May 2025 08:24:24 +0900 Subject: [PATCH 2/8] Emit getelementptr nuw for IndexExp in static array with const exp --- gen/toir.cpp | 11 ++++++++++- gen/tollvm.cpp | 13 +++++++++++-- gen/tollvm.h | 6 +++++- tests/codegen/inbounds.d | 2 +- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index e7105b51bd7..6fb33ea55d6 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1198,7 +1198,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) + 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); diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index c1fac2b98a4..fd5a5f91092 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -428,10 +428,19 @@ LLValue *DtoGEP(LLType *pointeeTy, LLValue *ptr, unsigned i0, unsigned i1, } 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, diff --git a/gen/tollvm.h b/gen/tollvm.h index 291c9209801..373c91f8448 100644 --- a/gen/tollvm.h +++ b/gen/tollvm.h @@ -102,7 +102,11 @@ LLValue *DtoGEP(LLType *pointeeTy, LLValue *ptr, unsigned i0, unsigned i1, #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 diff --git a/tests/codegen/inbounds.d b/tests/codegen/inbounds.d index b331cde5676..6394b1461af 100644 --- a/tests/codegen/inbounds.d +++ b/tests/codegen/inbounds.d @@ -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]; } From aae8dfc5de61826a535c6c040b726db6f9141deb Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Mon, 19 May 2025 09:55:21 +0900 Subject: [PATCH 3/8] Emit getelementptr nuw for SliceExp for static array with const lower bound --- gen/toir.cpp | 12 ++++++++++-- tests/codegen/inbounds.d | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index 6fb33ea55d6..1a2ea767fca 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1301,8 +1301,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) + 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/tests/codegen/inbounds.d b/tests/codegen/inbounds.d index 6394b1461af..86be0f15d61 100644 --- a/tests/codegen/inbounds.d +++ b/tests/codegen/inbounds.d @@ -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 .. $]; } From 2a438ddd9918972fb961b48701a39c235c6f480e Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Mon, 19 May 2025 20:01:40 +0900 Subject: [PATCH 4/8] Style fix --- gen/toir.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index 1a2ea767fca..28f8331e834 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1551,10 +1551,12 @@ class ToElemVisitor : public Visitor { auto nw = llvm::GEPNoWrapFlags::inBounds(); if (e->op == EXP::plusPlus) nw |= llvm::GEPNoWrapFlags::noUnsignedWrap(); - post = DtoGEP1(DtoMemType(dv->type->nextOf()), val, offset, "", p->scopebb(), nw); -#else - post = DtoGEP1(DtoMemType(dv->type->nextOf()), val, offset, "", p->scopebb()); #endif + post = DtoGEP1(DtoMemType(dv->type->nextOf()), val, offset, "", p->scopebb() +#if LDC_LLVM_VER >= 2000 + , nw +#endif + ); } else if (e1type->isComplex()) { assert(e2type->isComplex()); LLValue *one = LLConstantFP::get(DtoComplexBaseType(e1type), 1.0); From 2931faadf699d6b3ee6efdf6edf3eceb6f86729c Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Tue, 20 May 2025 08:41:55 +0900 Subject: [PATCH 5/8] Emit getelementptr nuw for adding offset to pointer --- gen/binops.cpp | 11 ++++++++++- tests/codegen/inbounds.d | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gen/binops.cpp b/gen/binops.cpp index f0012f1a390..f09176efca3 100644 --- a/gen/binops.cpp +++ b/gen/binops.cpp @@ -116,7 +116,16 @@ DValue *emitPointerOffset(Loc loc, DValue *base, Expression *offset, if (!llResult) { if (negateOffset) llOffset = gIR->ir->CreateNeg(llOffset); - llResult = DtoGEP1(llBaseTy, llBase, llOffset); +#if LDC_LLVM_VER >= 2000 + llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds(); + if (!negateOffset) + nw |= llvm::GEPNoWrapFlags::noUnsignedWrap(); +#endif + llResult = DtoGEP1(llBaseTy, llBase, llOffset +#if LDC_LLVM_VER >= 2000 + , "", nullptr, nw +#endif + ); } return new DImValue(resultType, llResult); diff --git a/tests/codegen/inbounds.d b/tests/codegen/inbounds.d index 86be0f15d61..404463240e7 100644 --- a/tests/codegen/inbounds.d +++ b/tests/codegen/inbounds.d @@ -37,14 +37,14 @@ int foo4(int* p) { // PreExp in pointer // CHECK-LABEL: @foo5 int foo5(int* p) { - // CHECK: getelementptr inbounds + // CHECK: getelementptr inbounds{{( nuw)?}} return *++p; } // Add offset to pointer // CHECK-LABEL: @foo6 int foo6(int* p, int i) { - // CHECK: getelementptr inbounds + // CHECK: getelementptr inbounds{{( nuw)?}} return *(p + i); } From cc5e8cf9633ae61103ed35cb5bfecc3998d76be5 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Tue, 20 May 2025 19:58:49 +0900 Subject: [PATCH 6/8] Emit getelementptr nuw for Struct field --- gen/llvmhelpers.cpp | 14 ++++++++++++-- tests/codegen/inbounds.d | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 198bb23ed78..6200ffc2415 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1870,7 +1870,12 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad, LLType * ty = nullptr; 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 + , llvm::GEPNoWrapFlags::inBounds() | llvm::GEPNoWrapFlags::noUnsignedWrap() +#endif + ); ty = DtoType(vd->type); } else { if (ad->structsize == 0) { // can happen for extern(C) structs @@ -1884,7 +1889,12 @@ 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 + , llvm::GEPNoWrapFlags::inBounds() | llvm::GEPNoWrapFlags::noUnsignedWrap() +#endif + ); ty = isaStruct(st)->getElementType(off); } } diff --git a/tests/codegen/inbounds.d b/tests/codegen/inbounds.d index 404463240e7..9dee8d71693 100644 --- a/tests/codegen/inbounds.d +++ b/tests/codegen/inbounds.d @@ -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; } From 3ce0b15f0cf4f7f33dfc91304126143226345976 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Wed, 21 May 2025 08:56:38 +0900 Subject: [PATCH 7/8] remove getelement nuw flag from pointer arithmetic; too aggresive --- gen/binops.cpp | 11 +---------- gen/toir.cpp | 11 +---------- tests/codegen/inbounds.d | 6 +++--- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/gen/binops.cpp b/gen/binops.cpp index f09176efca3..f0012f1a390 100644 --- a/gen/binops.cpp +++ b/gen/binops.cpp @@ -116,16 +116,7 @@ DValue *emitPointerOffset(Loc loc, DValue *base, Expression *offset, if (!llResult) { if (negateOffset) llOffset = gIR->ir->CreateNeg(llOffset); -#if LDC_LLVM_VER >= 2000 - llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds(); - if (!negateOffset) - nw |= llvm::GEPNoWrapFlags::noUnsignedWrap(); -#endif - llResult = DtoGEP1(llBaseTy, llBase, llOffset -#if LDC_LLVM_VER >= 2000 - , "", nullptr, nw -#endif - ); + llResult = DtoGEP1(llBaseTy, llBase, llOffset); } return new DImValue(resultType, llResult); diff --git a/gen/toir.cpp b/gen/toir.cpp index 28f8331e834..a06b2b95fc9 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1547,16 +1547,7 @@ class ToElemVisitor : public Visitor { assert(e->e2->op == EXP::int64); LLConstant *offset = e->op == EXP::plusPlus ? DtoConstUint(1) : DtoConstInt(-1); -#if LDC_LLVM_VER >= 2000 - auto nw = llvm::GEPNoWrapFlags::inBounds(); - if (e->op == EXP::plusPlus) - nw |= llvm::GEPNoWrapFlags::noUnsignedWrap(); -#endif - post = DtoGEP1(DtoMemType(dv->type->nextOf()), val, offset, "", p->scopebb() -#if LDC_LLVM_VER >= 2000 - , nw -#endif - ); + post = DtoGEP1(DtoMemType(dv->type->nextOf()), val, offset, "", p->scopebb()); } else if (e1type->isComplex()) { assert(e2type->isComplex()); LLValue *one = LLConstantFP::get(DtoComplexBaseType(e1type), 1.0); diff --git a/tests/codegen/inbounds.d b/tests/codegen/inbounds.d index 9dee8d71693..e92b7bd476d 100644 --- a/tests/codegen/inbounds.d +++ b/tests/codegen/inbounds.d @@ -30,21 +30,21 @@ int foo3(int* p, int i) { // PostExp in pointer // CHECK-LABEL: @foo4 int foo4(int* p) { - // CHECK: getelementptr inbounds{{( nuw)?}} + // CHECK: getelementptr inbounds return *p++; } // PreExp in pointer // CHECK-LABEL: @foo5 int foo5(int* p) { - // CHECK: getelementptr inbounds{{( nuw)?}} + // CHECK: getelementptr inbounds return *++p; } // Add offset to pointer // CHECK-LABEL: @foo6 int foo6(int* p, int i) { - // CHECK: getelementptr inbounds{{( nuw)?}} + // CHECK: getelementptr inbounds return *(p + i); } From e29f03a36176b353e61b8a7f64ec639b126e5270 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sun, 31 Aug 2025 12:27:10 +0900 Subject: [PATCH 8/8] Add enable-getelementptr-nuw flag --- driver/cl_options.cpp | 5 +++++ driver/cl_options.h | 2 ++ gen/llvmhelpers.cpp | 12 ++++++++---- gen/toir.cpp | 5 +++-- tests/codegen/inbounds.d | 2 +- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp index d230bc0f12e..85921844119 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 01596ccc8e3..0d8a2f526dc 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 6200ffc2415..e39cb321b75 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,12 +1869,16 @@ 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 #if LDC_LLVM_VER >= 2000 - , "", nullptr - , llvm::GEPNoWrapFlags::inBounds() | llvm::GEPNoWrapFlags::noUnsignedWrap() + , "", nullptr, nw #endif ); ty = DtoType(vd->type); @@ -1891,8 +1896,7 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad, } ptr = DtoGEP(st, ptr, 0, off #if LDC_LLVM_VER >= 2000 - , "", nullptr - , llvm::GEPNoWrapFlags::inBounds() | llvm::GEPNoWrapFlags::noUnsignedWrap() + , "", nullptr, nw #endif ); ty = isaStruct(st)->getElementType(off); diff --git a/gen/toir.cpp b/gen/toir.cpp index a06b2b95fc9..975a61bdf4c 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" @@ -1200,7 +1201,7 @@ class ToElemVisitor : public Visitor { LLType *arrty = llvm::ArrayType::get(elt, e1type->isTypeSArray()->dim->isIntegerExp()->getInteger()); #if LDC_LLVM_VER >= 2000 llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds(); - if (e->indexIsInBounds) + if (e->indexIsInBounds && opts::enableGetElementPtrNuw) nw |= llvm::GEPNoWrapFlags::noUnsignedWrap(); #endif arrptr = DtoGEP(arrty, DtoLVal(l), DtoConstUint(0), DtoRVal(r) @@ -1303,7 +1304,7 @@ class ToElemVisitor : public Visitor { // offset by lower #if LDC_LLVM_VER >= 2000 llvm::GEPNoWrapFlags nw = llvm::GEPNoWrapFlags::inBounds(); - if (!needCheckUpper && !needCheckLower) + if (!needCheckUpper && !needCheckLower && opts::enableGetElementPtrNuw) nw |= llvm::GEPNoWrapFlags::noUnsignedWrap(); #endif eptr = DtoGEP1(DtoMemType(etype->nextOf()), getBasePointer(), vlo, "lowerbound" diff --git a/tests/codegen/inbounds.d b/tests/codegen/inbounds.d index e92b7bd476d..3683448735f 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;