From 4f51adc8109395b0958405b675fb46c21a545786 Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Thu, 26 Feb 2009 22:47:06 +0100 Subject: [PATCH] Implement support for intrinsics returning struct types (such as llvm.*.with.overflow) --- gen/functions.cpp | 34 ++++++++++++++++++---------- gen/tocall.cpp | 18 +++++++++++++-- runtime/import/ldc/intrinsics.di | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/gen/functions.cpp b/gen/functions.cpp index 56790dc5..1b439e16 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -70,23 +70,33 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co else { assert(rt); - if (gABI->returnInArg(rt)) + if (f->linkage == LINKintrinsic) { - rettype = getPtrToType(DtoType(rt)); - actualRettype = LLType::VoidTy; - f->retInPtr = retinptr = true; + // Intrinsics don't care about ABI + Logger::cout() << "Intrinsic returning " << rt->toChars() << '\n'; + actualRettype = rettype = DtoType(rt); + Logger::cout() << " (LLVM type: " << *rettype << ")\n"; } else { - rettype = DtoType(rt); - // do abi specific transformations - actualRettype = gABI->getRetType(f, rettype); - } + if (gABI->returnInArg(rt)) + { + rettype = getPtrToType(DtoType(rt)); + actualRettype = LLType::VoidTy; + f->retInPtr = retinptr = true; + } + else + { + rettype = DtoType(rt); + // do abi specific transformations + actualRettype = gABI->getRetType(f, rettype); + } - // FIXME: should probably be part of the abi - if (unsigned ea = DtoShouldExtend(rt)) - { - f->retAttrs |= ea; + // FIXME: should probably be part of the abi + if (unsigned ea = DtoShouldExtend(rt)) + { + f->retAttrs |= ea; + } } } diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 9b1bbfc1..b51e2028 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -464,8 +464,22 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // get return value LLValue* retllval = (retinptr) ? args[0] : call->get(); - // do abi specific return value fixups - retllval = gABI->getRet(tf, retllval); + if (tf->linkage == LINKintrinsic) + { + // Ignore ABI for intrinsics + Type* rettype = tf->next; + if (rettype->ty == Tstruct) { + // LDC assumes structs are in memory, so put it there. + LLValue* mem = DtoAlloca(retllval->getType()); + DtoStore(retllval, mem); + retllval = mem; + } + } + else + { + // do abi specific return value fixups + retllval = gABI->getRet(tf, retllval); + } // repaint the type if necessary if (resulttype) diff --git a/runtime/import/ldc/intrinsics.di b/runtime/import/ldc/intrinsics.di index fbdbc4f6..ffeb8ea2 100644 --- a/runtime/import/ldc/intrinsics.di +++ b/runtime/import/ldc/intrinsics.di @@ -332,6 +332,45 @@ pragma(intrinsic, "llvm.atomic.load.umax.i#.p0i#") pragma(intrinsic, "llvm.atomic.load.umin.i#.p0i#") T llvm_atomic_load_umin(T)(T* ptr, T val); + +// +// ARITHMETIC-WITH-OVERFLOW INTRINSICS +// + +struct OverflowRet(T) { + static assert(is(T : int), T.stringof ~ " is not an integer type!"); + T result; + bool overflow; +} + +// Signed and unsigned addition +pragma(intrinsic, "llvm.sadd.with.overflow.i#") + OverflowRet!(T) llvm_sadd_with_overflow(T)(T lhs, T rhs); + +pragma(intrinsic, "llvm.uadd.with.overflow.i#") + OverflowRet!(T) llvm_uadd_with_overflow(T)(T lhs, T rhs); + +// Signed and unsigned subtraction +pragma(intrinsic, "llvm.ssub.with.overflow.i#") + OverflowRet!(T) llvm_ssub_with_overflow(T)(T lhs, T rhs); + +pragma(intrinsic, "llvm.usub.with.overflow.i#") + OverflowRet!(T) llvm_usub_with_overflow(T)(T lhs, T rhs); + +// Signed and unsigned multiplication +pragma(intrinsic, "llvm.smul.with.overflow.i#") + OverflowRet!(T) llvm_smul_with_overflow(T)(T lhs, T rhs); + +/* Note: LLVM documentations says: + * Warning: 'llvm.umul.with.overflow' is badly broken. + * It is actively being fixed, but it should not currently be used! + * + * See: http://llvm.org/docs/LangRef.html#int_umul_overflow + */ +pragma(intrinsic, "llvm.umul.with.overflow.i#") + OverflowRet!(T) llvm_umul_with_overflow(T)(T lhs, T rhs); + + // // GENERAL INTRINSICS //