Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
213799 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This contains code to emit Builtin calls as CIR or a function call to be9// later resolved.10//11//===----------------------------------------------------------------------===//1213#include "CIRGenCall.h"14#include "CIRGenConstantEmitter.h"15#include "CIRGenFunction.h"16#include "CIRGenModule.h"17#include "CIRGenValue.h"18#include "mlir/IR/BuiltinAttributes.h"19#include "mlir/IR/Value.h"20#include "mlir/Support/LLVM.h"21#include "clang/AST/Expr.h"22#include "clang/AST/GlobalDecl.h"23#include "clang/CIR/MissingFeatures.h"24#include "llvm/Support/ErrorHandling.h"2526using namespace clang;27using namespace clang::CIRGen;28using namespace llvm;2930static RValue emitLibraryCall(CIRGenFunction &cgf, const FunctionDecl *fd,31const CallExpr *e, mlir::Operation *calleeValue) {32CIRGenCallee callee = CIRGenCallee::forDirect(calleeValue, GlobalDecl(fd));33return cgf.emitCall(e->getCallee()->getType(), callee, e, ReturnValueSlot());34}3536template <typename Op>37static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e,38bool poisonZero = false) {39assert(!cir::MissingFeatures::builtinCheckKind());4041mlir::Value arg = cgf.emitScalarExpr(e->getArg(0));42CIRGenBuilderTy &builder = cgf.getBuilder();4344Op op;45if constexpr (std::is_same_v<Op, cir::BitClzOp> ||46std::is_same_v<Op, cir::BitCtzOp>)47op = builder.create<Op>(cgf.getLoc(e->getSourceRange()), arg, poisonZero);48else49op = builder.create<Op>(cgf.getLoc(e->getSourceRange()), arg);5051mlir::Value result = op.getResult();52mlir::Type exprTy = cgf.convertType(e->getType());53if (exprTy != result.getType())54result = builder.createIntCast(result, exprTy);5556return RValue::get(result);57}5859RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,60const CallExpr *e,61ReturnValueSlot returnValue) {62mlir::Location loc = getLoc(e->getSourceRange());6364// See if we can constant fold this builtin. If so, don't emit it at all.65// TODO: Extend this handling to all builtin calls that we can constant-fold.66Expr::EvalResult result;67if (e->isPRValue() && e->EvaluateAsRValue(result, cgm.getASTContext()) &&68!result.hasSideEffects()) {69if (result.Val.isInt())70return RValue::get(builder.getConstInt(loc, result.Val.getInt()));71if (result.Val.isFloat()) {72// Note: we are using result type of CallExpr to determine the type of73// the constant. Classic codegen uses the result value to determine the74// type. We feel it should be Ok to use expression type because it is75// hard to imagine a builtin function evaluates to a value that76// over/underflows its own defined type.77mlir::Type type = convertType(e->getType());78return RValue::get(builder.getConstFP(loc, type, result.Val.getFloat()));79}80}8182const FunctionDecl *fd = gd.getDecl()->getAsFunction();8384assert(!cir::MissingFeatures::builtinCallF128());8586// If the builtin has been declared explicitly with an assembler label,87// disable the specialized emitting below. Ideally we should communicate the88// rename in IR, or at least avoid generating the intrinsic calls that are89// likely to get lowered to the renamed library functions.90unsigned builtinIDIfNoAsmLabel = fd->hasAttr<AsmLabelAttr>() ? 0 : builtinID;9192assert(!cir::MissingFeatures::builtinCallMathErrno());93assert(!cir::MissingFeatures::builtinCall());9495switch (builtinIDIfNoAsmLabel) {96default:97break;9899case Builtin::BI__assume:100case Builtin::BI__builtin_assume: {101if (e->getArg(0)->HasSideEffects(getContext()))102return RValue::get(nullptr);103104mlir::Value argValue = emitCheckedArgForAssume(e->getArg(0));105builder.create<cir::AssumeOp>(loc, argValue);106return RValue::get(nullptr);107}108109case Builtin::BI__builtin_complex: {110mlir::Value real = emitScalarExpr(e->getArg(0));111mlir::Value imag = emitScalarExpr(e->getArg(1));112mlir::Value complex = builder.createComplexCreate(loc, real, imag);113return RValue::get(complex);114}115116case Builtin::BI__builtin_creal:117case Builtin::BI__builtin_crealf:118case Builtin::BI__builtin_creall:119case Builtin::BIcreal:120case Builtin::BIcrealf:121case Builtin::BIcreall: {122mlir::Value complex = emitComplexExpr(e->getArg(0));123mlir::Value real = builder.createComplexReal(loc, complex);124return RValue::get(real);125}126127case Builtin::BI__builtin_cimag:128case Builtin::BI__builtin_cimagf:129case Builtin::BI__builtin_cimagl:130case Builtin::BIcimag:131case Builtin::BIcimagf:132case Builtin::BIcimagl: {133mlir::Value complex = emitComplexExpr(e->getArg(0));134mlir::Value imag = builder.createComplexImag(loc, complex);135return RValue::get(imag);136}137138case Builtin::BI__builtin_clrsb:139case Builtin::BI__builtin_clrsbl:140case Builtin::BI__builtin_clrsbll:141return emitBuiltinBitOp<cir::BitClrsbOp>(*this, e);142143case Builtin::BI__builtin_ctzs:144case Builtin::BI__builtin_ctz:145case Builtin::BI__builtin_ctzl:146case Builtin::BI__builtin_ctzll:147case Builtin::BI__builtin_ctzg:148assert(!cir::MissingFeatures::builtinCheckKind());149return emitBuiltinBitOp<cir::BitCtzOp>(*this, e, /*poisonZero=*/true);150151case Builtin::BI__builtin_clzs:152case Builtin::BI__builtin_clz:153case Builtin::BI__builtin_clzl:154case Builtin::BI__builtin_clzll:155case Builtin::BI__builtin_clzg:156assert(!cir::MissingFeatures::builtinCheckKind());157return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/true);158159case Builtin::BI__builtin_parity:160case Builtin::BI__builtin_parityl:161case Builtin::BI__builtin_parityll:162return emitBuiltinBitOp<cir::BitParityOp>(*this, e);163164case Builtin::BI__lzcnt16:165case Builtin::BI__lzcnt:166case Builtin::BI__lzcnt64:167assert(!cir::MissingFeatures::builtinCheckKind());168return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/false);169170case Builtin::BI__popcnt16:171case Builtin::BI__popcnt:172case Builtin::BI__popcnt64:173case Builtin::BI__builtin_popcount:174case Builtin::BI__builtin_popcountl:175case Builtin::BI__builtin_popcountll:176case Builtin::BI__builtin_popcountg:177return emitBuiltinBitOp<cir::BitPopcountOp>(*this, e);178179case Builtin::BI__builtin_expect:180case Builtin::BI__builtin_expect_with_probability: {181mlir::Value argValue = emitScalarExpr(e->getArg(0));182mlir::Value expectedValue = emitScalarExpr(e->getArg(1));183184mlir::FloatAttr probAttr;185if (builtinIDIfNoAsmLabel == Builtin::BI__builtin_expect_with_probability) {186llvm::APFloat probability(0.0);187const Expr *probArg = e->getArg(2);188[[maybe_unused]] bool evalSucceeded =189probArg->EvaluateAsFloat(probability, cgm.getASTContext());190assert(evalSucceeded &&191"probability should be able to evaluate as float");192bool loseInfo = false; // ignored193probability.convert(llvm::APFloat::IEEEdouble(),194llvm::RoundingMode::Dynamic, &loseInfo);195probAttr = mlir::FloatAttr::get(mlir::Float64Type::get(&getMLIRContext()),196probability);197}198199auto result = builder.create<cir::ExpectOp>(200loc, argValue.getType(), argValue, expectedValue, probAttr);201return RValue::get(result);202}203204case Builtin::BI__builtin_bswap16:205case Builtin::BI__builtin_bswap32:206case Builtin::BI__builtin_bswap64:207case Builtin::BI_byteswap_ushort:208case Builtin::BI_byteswap_ulong:209case Builtin::BI_byteswap_uint64: {210mlir::Value arg = emitScalarExpr(e->getArg(0));211return RValue::get(builder.create<cir::ByteSwapOp>(loc, arg));212}213214case Builtin::BI__builtin_bitreverse8:215case Builtin::BI__builtin_bitreverse16:216case Builtin::BI__builtin_bitreverse32:217case Builtin::BI__builtin_bitreverse64: {218mlir::Value arg = emitScalarExpr(e->getArg(0));219return RValue::get(builder.create<cir::BitReverseOp>(loc, arg));220}221}222223// If this is an alias for a lib function (e.g. __builtin_sin), emit224// the call using the normal call path, but using the unmangled225// version of the function name.226if (getContext().BuiltinInfo.isLibFunction(builtinID))227return emitLibraryCall(*this, fd, e,228cgm.getBuiltinLibFunction(fd, builtinID));229230cgm.errorNYI(e->getSourceRange(), "unimplemented builtin call");231return getUndefRValue(e->getType());232}233234/// Given a builtin id for a function like "__builtin_fabsf", return a Function*235/// for "fabsf".236cir::FuncOp CIRGenModule::getBuiltinLibFunction(const FunctionDecl *fd,237unsigned builtinID) {238assert(astContext.BuiltinInfo.isLibFunction(builtinID));239240// Get the name, skip over the __builtin_ prefix (if necessary). We may have241// to build this up so provide a small stack buffer to handle the vast242// majority of names.243llvm::SmallString<64> name;244245assert(!cir::MissingFeatures::asmLabelAttr());246name = astContext.BuiltinInfo.getName(builtinID).substr(10);247248GlobalDecl d(fd);249mlir::Type type = convertType(fd->getType());250return getOrCreateCIRFunction(name, type, d, /*forVTable=*/false);251}252253mlir::Value CIRGenFunction::emitCheckedArgForAssume(const Expr *e) {254mlir::Value argValue = evaluateExprAsBool(e);255if (!sanOpts.has(SanitizerKind::Builtin))256return argValue;257258assert(!cir::MissingFeatures::sanitizers());259cgm.errorNYI(e->getSourceRange(),260"emitCheckedArgForAssume: sanitizers are NYI");261return {};262}263264265