Implement support for intrinsics returning struct types

(such as llvm.*.with.overflow)
This commit is contained in:
Frits van Bommel
2009-02-26 22:47:06 +01:00
parent 693e796893
commit 4f51adc810
3 changed files with 77 additions and 14 deletions

View File

@@ -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;
}
}
}

View File

@@ -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)

View File

@@ -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
//