diff options
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGBuiltin.cpp | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 55f2757ccd..9badeaf613 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -169,6 +169,31 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn, ReturnValueSlot(), E->arg_begin(), E->arg_end(), Fn); } +/// \brief Emit a call to llvm.{sadd,uadd,ssub,usub,smul,umul}.with.overflow.* +/// depending on IntrinsicID. +/// +/// \arg CGF The current codegen function. +/// \arg IntrinsicID The ID for the Intrinsic we wish to generate. +/// \arg X The first argument to the llvm.*.with.overflow.*. +/// \arg Y The second argument to the llvm.*.with.overflow.*. +/// \arg Carry The carry returned by the llvm.*.with.overflow.*. +/// \returns The result (i.e. sum/product) returned by the intrinsic. +static llvm::Value *EmitOverflowIntrinsic(CodeGenFunction &CGF, + const llvm::Intrinsic::ID IntrinsicID, + llvm::Value *X, llvm::Value *Y, + llvm::Value *&Carry) { + // Make sure we have integers of the same width. + assert(X->getType() == Y->getType() && + "Arguments must be the same type. (Did you forget to make sure both " + "arguments have the same integer width?)"); + + ArrayRef<llvm::Type *> Type(X->getType()); + llvm::Value *Callee = CGF.CGM.getIntrinsic(IntrinsicID, Type); + llvm::Value *Tmp = CGF.Builder.CreateCall2(Callee, X, Y); + Carry = CGF.Builder.CreateExtractValue(Tmp, 1); + return CGF.Builder.CreateExtractValue(Tmp, 0); +} + RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E) { // See if we can constant fold this builtin. If so, don't emit it at all. @@ -1321,6 +1346,51 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString(); return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc())); } + case Builtin::BI__builtin_addcs: + case Builtin::BI__builtin_addc: + case Builtin::BI__builtin_addcl: + case Builtin::BI__builtin_addcll: { + + // We translate all of these builtins from expressions of the form: + // int x = ..., y = ..., carryin = ..., carryout, result; + // result = __builtin_addc(x, y, carryin, &carryout); + // + // to LLVM IR of the form: + // + // %tmp1 = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %x, i32 %y) + // %tmpsum1 = extractvalue {i32, i1} %tmp1, 0 + // %carry1 = extractvalue {i32, i1} %tmp1, 1 + // %tmp2 = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %tmpsum1, + // i32 %carryin) + // %result = extractvalue {i32, i1} %tmp2, 0 + // %carry2 = extractvalue {i32, i1} %tmp2, 1 + // %tmp3 = or i1 %carry1, %carry2 + // %tmp4 = zext i1 %tmp3 to i32 + // store i32 %tmp4, i32* %carryout + + // Scalarize our inputs. + llvm::Value *X = EmitScalarExpr(E->getArg(0)); + llvm::Value *Y = EmitScalarExpr(E->getArg(1)); + llvm::Value *Carryin = EmitScalarExpr(E->getArg(2)); + std::pair<llvm::Value*, unsigned> CarryOutPtr = + EmitPointerWithAlignment(E->getArg(3)); + + const llvm::Intrinsic::ID IntrinsicId = llvm::Intrinsic::uadd_with_overflow; + + // Construct our resulting LLVM IR expression. + llvm::Value *Carry1; + llvm::Value *Sum1 = EmitOverflowIntrinsic(*this, IntrinsicId, + X, Y, Carry1); + llvm::Value *Carry2; + llvm::Value *Sum2 = EmitOverflowIntrinsic(*this, IntrinsicId, + Sum1, Carryin, Carry2); + llvm::Value *CarryOut = Builder.CreateZExt(Builder.CreateOr(Carry1, Carry2), + X->getType()); + llvm::StoreInst *CarryOutStore = Builder.CreateStore(CarryOut, + CarryOutPtr.first); + CarryOutStore->setAlignment(CarryOutPtr.second); + return RValue::get(Sum2); + } case Builtin::BI__noop: return RValue::get(0); } |