diff --git a/CHANGELOG.md b/CHANGELOG.md index de9002914d1..5a9809c9d74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Supports LLVM 11.0 - 15.0. #### Bug fixes +- Fix function pointers/delegates on Harvard architectures (e.g., AVR). (#4432, #4465) # LDC 1.33.0 (2023-07-23) diff --git a/gen/declarations.cpp b/gen/declarations.cpp index c0d2ad3ad47..d98652a2ebb 100644 --- a/gen/declarations.cpp +++ b/gen/declarations.cpp @@ -419,17 +419,16 @@ class CodegenVisitor : public Visitor { std::string arg = ("/DEFAULTLIB:\"" + name + "\"").str(); gIR->addLinkerOption(llvm::StringRef(arg)); } else { - bool isStaticLib = name.endswith(".a"); + const bool isStaticLib = name.endswith(".a"); + const size_t nameLen = name.size(); - size_t const nameLen = name.size(); - size_t const n = nameLen + 3; char *arg = nullptr; - - if (isStaticLib == false) { + if (!isStaticLib) { // name => -lname + const size_t n = nameLen + 3; arg = static_cast(mem.xmalloc(n)); arg[0] = '-'; arg[1] = 'l'; - memcpy(arg + 2, name.data(), name.size()); + memcpy(arg + 2, name.data(), nameLen); arg[n - 1] = 0; } else { arg = static_cast((mem.xmalloc(nameLen + 1))); diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 47259c3d596..615aa7ba3ea 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -819,7 +819,7 @@ class ImplicitArgumentsBuilder { //////////////////////////////////////////////////////////////////////////////// -static LLValue *DtoCallableValue(llvm::FunctionType * ft,DValue *fn) { +static LLValue *DtoCallableValue(DValue *fn) { Type *type = fn->type->toBasetype(); if (type->ty == TY::Tfunction) { return DtoRVal(fn); @@ -829,7 +829,7 @@ static LLValue *DtoCallableValue(llvm::FunctionType * ft,DValue *fn) { LLValue *dg = DtoLVal(fn); llvm::StructType *st = isaStruct(DtoType(fn->type)); LLValue *funcptr = DtoGEP(st, dg, 0, 1); - return DtoLoad(ft->getPointerTo(), funcptr, ".funcptr"); + return DtoLoad(st->getElementType(1), funcptr, ".funcptr"); } LLValue *dg = DtoRVal(fn); assert(isaStruct(dg)); @@ -862,7 +862,7 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval, } // get callee llvm value - LLValue *callable = DtoCallableValue(irFty.funcType, fnval); + LLValue *callable = DtoCallableValue(fnval); LLFunctionType *callableTy = irFty.funcType; if (dfnval && dfnval->func->isCsymbol()) { // See note in DtoDeclareFunction about K&R foward declared (void) functions diff --git a/ir/irtype.cpp b/ir/irtype.cpp index 0cf987d9284..d00f35c5386 100644 --- a/ir/irtype.cpp +++ b/ir/irtype.cpp @@ -118,10 +118,14 @@ IrTypePointer *IrTypePointer::get(Type *dt) { assert(!ctype); LLType *elemType; + unsigned addressSpace = 0; if (dt->ty == TY::Tnull) { elemType = llvm::Type::getInt8Ty(getGlobalContext()); } else { elemType = DtoMemType(dt->nextOf()); + if (dt->nextOf()->ty == TY::Tfunction) { + addressSpace = gDataLayout->getProgramAddressSpace(); + } // DtoType could have already created the same type, e.g. for // dt == Node* in struct Node { Node* n; }. @@ -130,7 +134,8 @@ IrTypePointer *IrTypePointer::get(Type *dt) { } } - auto t = new IrTypePointer(dt, llvm::PointerType::get(elemType, 0)); + auto t = + new IrTypePointer(dt, llvm::PointerType::get(elemType, addressSpace)); ctype = t; return t; } diff --git a/ir/irtypefunction.cpp b/ir/irtypefunction.cpp index 8a1a4ba9a9d..0e830f187af 100644 --- a/ir/irtypefunction.cpp +++ b/ir/irtypefunction.cpp @@ -53,7 +53,8 @@ IrTypeDelegate *IrTypeDelegate::get(Type *t) { IrFuncTy irFty(tf); llvm::Type *ltf = DtoFunctionType(tf, irFty, nullptr, Type::tvoid->pointerTo()); - llvm::Type *types[] = {getVoidPtrType(), getPtrToType(ltf)}; + llvm::Type *fptr = ltf->getPointerTo(gDataLayout->getProgramAddressSpace()); + llvm::Type *types[] = {getVoidPtrType(), fptr}; LLStructType *lt = LLStructType::get(gIR->context(), types, false); // Could have already built the type as part of a struct forward reference, diff --git a/tests/codegen/funcptr_harvard_gh4432.d b/tests/codegen/funcptr_harvard_gh4432.d new file mode 100644 index 00000000000..9400d982b07 --- /dev/null +++ b/tests/codegen/funcptr_harvard_gh4432.d @@ -0,0 +1,37 @@ +// Tests function pointers/delegates on a Harvard architecture, +// with code residing in a separate address space. + +// REQUIRES: target_AVR +// RUN: %ldc -mtriple=avr -betterC -output-ll -of=%t.ll %s && FileCheck %s < %t.ll +// RUN: %ldc -mtriple=avr -betterC -c %s + +alias FP = void function(); +alias DG = void delegate(); + +// CHECK: @_D22funcptr_harvard_gh44328globalFPPFZv = global {{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}} @_D22funcptr_harvard_gh44323barFZv, align 2 +__gshared FP globalFP = &bar; +// CHECK: @_D22funcptr_harvard_gh443217globalDataPointerPPFZv = global {{void \(\) addrspace\(1\)\*\*|ptr}} @_D22funcptr_harvard_gh44328globalFPPFZv, align 2 +__gshared FP* globalDataPointer = &globalFP; + +// CHECK: define void @_D22funcptr_harvard_gh44323fooFPFZvDQeZv({{.*}} addrspace(1){{\*?}} %fp_arg, { {{.*}} addrspace(1){{\*?}} } %dg_arg) addrspace(1) +void foo(FP fp, DG dg) +{ + // CHECK: call addrspace(1) void %1() + fp(); + // CHECK: call addrspace(1) void %.funcptr + dg(); + // CHECK-NEXT: ret void +} + +void bar() +{ + foo(() {}, delegate() {}); + + FP fp = &bar; + DG dg; + dg.funcptr = &bar; + foo(fp, dg); + + dg.funcptr = *globalDataPointer; + foo(globalFP, dg); +}