# HG changeset patch # User Frits van Bommel # Date 1235684826 -3600 # Node ID 7a0238db1962f8a1cb70ea8da4d5e41e46778784 # Parent d6895f24dc8fd7f253e5187e2a2474aac510aeba Implement support for intrinsics returning struct types (such as llvm.*.with.overflow) diff -r d6895f24dc8f -r 7a0238db1962 gen/functions.cpp --- a/gen/functions.cpp Thu Feb 26 18:43:25 2009 +0100 +++ b/gen/functions.cpp Thu Feb 26 22:47:06 2009 +0100 @@ -70,23 +70,33 @@ 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 -r d6895f24dc8f -r 7a0238db1962 gen/tocall.cpp --- a/gen/tocall.cpp Thu Feb 26 18:43:25 2009 +0100 +++ b/gen/tocall.cpp Thu Feb 26 22:47:06 2009 +0100 @@ -464,8 +464,22 @@ // 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 -r d6895f24dc8f -r 7a0238db1962 runtime/import/ldc/intrinsics.di --- a/runtime/import/ldc/intrinsics.di Thu Feb 26 18:43:25 2009 +0100 +++ b/runtime/import/ldc/intrinsics.di Thu Feb 26 22:47:06 2009 +0100 @@ -332,6 +332,45 @@ 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 //