From af6bf9d37efc1238cbfb1b5cd60e45c38d0d8e69 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Mon, 19 May 2025 06:07:50 +0900 Subject: [PATCH 1/7] 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 fc8d65a8543..8be341faa74 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1517,7 +1517,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 dde4a555ed409a8921e994c96c86a8081857f2ec Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Mon, 19 May 2025 08:24:24 +0900 Subject: [PATCH 2/7] 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 8be341faa74..90b86f34fd6 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1190,7 +1190,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 476fc56a08b522aa291f828fdf704a04b2fc55ac Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Mon, 19 May 2025 09:55:21 +0900 Subject: [PATCH 3/7] 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 90b86f34fd6..a74d6882579 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1293,8 +1293,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 6e81915810b9c5df6222e8a73ef138bf1270f04f Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Mon, 19 May 2025 20:01:40 +0900 Subject: [PATCH 4/7] Style fix --- gen/toir.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index a74d6882579..3ef51fa5e7f 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1538,10 +1538,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 2351bf317cd8e99032c79ab01a32d4c353560aa3 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Tue, 20 May 2025 08:41:55 +0900 Subject: [PATCH 5/7] 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 3efa40964465a9e5523c5ad7d3befda13e5583be Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Tue, 20 May 2025 19:58:49 +0900 Subject: [PATCH 6/7] 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 f7558238d3a..a33d0785e1a 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1860,7 +1860,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 @@ -1874,7 +1879,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 2c5cbc0b527a08b44924d21549667a2b266ceb9f Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Wed, 21 May 2025 08:56:38 +0900 Subject: [PATCH 7/7] 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 3ef51fa5e7f..603128ec798 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1534,16 +1534,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); }