mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-04-06 11:59:02 +02:00
Implement support for intrinsics returning struct types
(such as llvm.*.with.overflow)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user