1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This contains code to emit Builtin calls as CIR or a function call to be 10 // later resolved. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "CIRGenCall.h" 15 #include "CIRGenConstantEmitter.h" 16 #include "CIRGenFunction.h" 17 #include "CIRGenModule.h" 18 #include "CIRGenValue.h" 19 #include "mlir/IR/BuiltinAttributes.h" 20 #include "mlir/IR/Value.h" 21 #include "mlir/Support/LLVM.h" 22 #include "clang/AST/Expr.h" 23 #include "clang/AST/GlobalDecl.h" 24 #include "clang/CIR/MissingFeatures.h" 25 #include "llvm/Support/ErrorHandling.h" 26 27 using namespace clang; 28 using namespace clang::CIRGen; 29 using namespace llvm; 30 31 static RValue emitLibraryCall(CIRGenFunction &cgf, const FunctionDecl *fd, 32 const CallExpr *e, mlir::Operation *calleeValue) { 33 CIRGenCallee callee = CIRGenCallee::forDirect(calleeValue, GlobalDecl(fd)); 34 return cgf.emitCall(e->getCallee()->getType(), callee, e, ReturnValueSlot()); 35 } 36 37 template <typename Op> 38 static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e, 39 bool poisonZero = false) { 40 assert(!cir::MissingFeatures::builtinCheckKind()); 41 42 mlir::Value arg = cgf.emitScalarExpr(e->getArg(0)); 43 CIRGenBuilderTy &builder = cgf.getBuilder(); 44 45 Op op; 46 if constexpr (std::is_same_v<Op, cir::BitClzOp> || 47 std::is_same_v<Op, cir::BitCtzOp>) 48 op = builder.create<Op>(cgf.getLoc(e->getSourceRange()), arg, poisonZero); 49 else 50 op = builder.create<Op>(cgf.getLoc(e->getSourceRange()), arg); 51 52 mlir::Value result = op.getResult(); 53 mlir::Type exprTy = cgf.convertType(e->getType()); 54 if (exprTy != result.getType()) 55 result = builder.createIntCast(result, exprTy); 56 57 return RValue::get(result); 58 } 59 60 RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, 61 const CallExpr *e, 62 ReturnValueSlot returnValue) { 63 mlir::Location loc = getLoc(e->getSourceRange()); 64 65 // See if we can constant fold this builtin. If so, don't emit it at all. 66 // TODO: Extend this handling to all builtin calls that we can constant-fold. 67 Expr::EvalResult result; 68 if (e->isPRValue() && e->EvaluateAsRValue(result, cgm.getASTContext()) && 69 !result.hasSideEffects()) { 70 if (result.Val.isInt()) 71 return RValue::get(builder.getConstInt(loc, result.Val.getInt())); 72 if (result.Val.isFloat()) { 73 // Note: we are using result type of CallExpr to determine the type of 74 // the constant. Classic codegen uses the result value to determine the 75 // type. We feel it should be Ok to use expression type because it is 76 // hard to imagine a builtin function evaluates to a value that 77 // over/underflows its own defined type. 78 mlir::Type type = convertType(e->getType()); 79 return RValue::get(builder.getConstFP(loc, type, result.Val.getFloat())); 80 } 81 } 82 83 const FunctionDecl *fd = gd.getDecl()->getAsFunction(); 84 85 assert(!cir::MissingFeatures::builtinCallF128()); 86 87 // If the builtin has been declared explicitly with an assembler label, 88 // disable the specialized emitting below. Ideally we should communicate the 89 // rename in IR, or at least avoid generating the intrinsic calls that are 90 // likely to get lowered to the renamed library functions. 91 unsigned builtinIDIfNoAsmLabel = fd->hasAttr<AsmLabelAttr>() ? 0 : builtinID; 92 93 assert(!cir::MissingFeatures::builtinCallMathErrno()); 94 assert(!cir::MissingFeatures::builtinCall()); 95 96 switch (builtinIDIfNoAsmLabel) { 97 default: 98 break; 99 100 case Builtin::BI__assume: 101 case Builtin::BI__builtin_assume: { 102 if (e->getArg(0)->HasSideEffects(getContext())) 103 return RValue::get(nullptr); 104 105 mlir::Value argValue = emitCheckedArgForAssume(e->getArg(0)); 106 builder.create<cir::AssumeOp>(loc, argValue); 107 return RValue::get(nullptr); 108 } 109 110 case Builtin::BI__builtin_complex: { 111 mlir::Value real = emitScalarExpr(e->getArg(0)); 112 mlir::Value imag = emitScalarExpr(e->getArg(1)); 113 mlir::Value complex = builder.createComplexCreate(loc, real, imag); 114 return RValue::get(complex); 115 } 116 117 case Builtin::BI__builtin_creal: 118 case Builtin::BI__builtin_crealf: 119 case Builtin::BI__builtin_creall: 120 case Builtin::BIcreal: 121 case Builtin::BIcrealf: 122 case Builtin::BIcreall: { 123 mlir::Value complex = emitComplexExpr(e->getArg(0)); 124 mlir::Value real = builder.createComplexReal(loc, complex); 125 return RValue::get(real); 126 } 127 128 case Builtin::BI__builtin_cimag: 129 case Builtin::BI__builtin_cimagf: 130 case Builtin::BI__builtin_cimagl: 131 case Builtin::BIcimag: 132 case Builtin::BIcimagf: 133 case Builtin::BIcimagl: { 134 mlir::Value complex = emitComplexExpr(e->getArg(0)); 135 mlir::Value imag = builder.createComplexImag(loc, complex); 136 return RValue::get(imag); 137 } 138 139 case Builtin::BI__builtin_clrsb: 140 case Builtin::BI__builtin_clrsbl: 141 case Builtin::BI__builtin_clrsbll: 142 return emitBuiltinBitOp<cir::BitClrsbOp>(*this, e); 143 144 case Builtin::BI__builtin_ctzs: 145 case Builtin::BI__builtin_ctz: 146 case Builtin::BI__builtin_ctzl: 147 case Builtin::BI__builtin_ctzll: 148 case Builtin::BI__builtin_ctzg: 149 assert(!cir::MissingFeatures::builtinCheckKind()); 150 return emitBuiltinBitOp<cir::BitCtzOp>(*this, e, /*poisonZero=*/true); 151 152 case Builtin::BI__builtin_clzs: 153 case Builtin::BI__builtin_clz: 154 case Builtin::BI__builtin_clzl: 155 case Builtin::BI__builtin_clzll: 156 case Builtin::BI__builtin_clzg: 157 assert(!cir::MissingFeatures::builtinCheckKind()); 158 return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/true); 159 160 case Builtin::BI__builtin_parity: 161 case Builtin::BI__builtin_parityl: 162 case Builtin::BI__builtin_parityll: 163 return emitBuiltinBitOp<cir::BitParityOp>(*this, e); 164 165 case Builtin::BI__lzcnt16: 166 case Builtin::BI__lzcnt: 167 case Builtin::BI__lzcnt64: 168 assert(!cir::MissingFeatures::builtinCheckKind()); 169 return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/false); 170 171 case Builtin::BI__popcnt16: 172 case Builtin::BI__popcnt: 173 case Builtin::BI__popcnt64: 174 case Builtin::BI__builtin_popcount: 175 case Builtin::BI__builtin_popcountl: 176 case Builtin::BI__builtin_popcountll: 177 case Builtin::BI__builtin_popcountg: 178 return emitBuiltinBitOp<cir::BitPopcountOp>(*this, e); 179 180 case Builtin::BI__builtin_expect: 181 case Builtin::BI__builtin_expect_with_probability: { 182 mlir::Value argValue = emitScalarExpr(e->getArg(0)); 183 mlir::Value expectedValue = emitScalarExpr(e->getArg(1)); 184 185 mlir::FloatAttr probAttr; 186 if (builtinIDIfNoAsmLabel == Builtin::BI__builtin_expect_with_probability) { 187 llvm::APFloat probability(0.0); 188 const Expr *probArg = e->getArg(2); 189 [[maybe_unused]] bool evalSucceeded = 190 probArg->EvaluateAsFloat(probability, cgm.getASTContext()); 191 assert(evalSucceeded && 192 "probability should be able to evaluate as float"); 193 bool loseInfo = false; // ignored 194 probability.convert(llvm::APFloat::IEEEdouble(), 195 llvm::RoundingMode::Dynamic, &loseInfo); 196 probAttr = mlir::FloatAttr::get(mlir::Float64Type::get(&getMLIRContext()), 197 probability); 198 } 199 200 auto result = builder.create<cir::ExpectOp>( 201 loc, argValue.getType(), argValue, expectedValue, probAttr); 202 return RValue::get(result); 203 } 204 205 case Builtin::BI__builtin_bswap16: 206 case Builtin::BI__builtin_bswap32: 207 case Builtin::BI__builtin_bswap64: 208 case Builtin::BI_byteswap_ushort: 209 case Builtin::BI_byteswap_ulong: 210 case Builtin::BI_byteswap_uint64: { 211 mlir::Value arg = emitScalarExpr(e->getArg(0)); 212 return RValue::get(builder.create<cir::ByteSwapOp>(loc, arg)); 213 } 214 215 case Builtin::BI__builtin_bitreverse8: 216 case Builtin::BI__builtin_bitreverse16: 217 case Builtin::BI__builtin_bitreverse32: 218 case Builtin::BI__builtin_bitreverse64: { 219 mlir::Value arg = emitScalarExpr(e->getArg(0)); 220 return RValue::get(builder.create<cir::BitReverseOp>(loc, arg)); 221 } 222 } 223 224 // If this is an alias for a lib function (e.g. __builtin_sin), emit 225 // the call using the normal call path, but using the unmangled 226 // version of the function name. 227 if (getContext().BuiltinInfo.isLibFunction(builtinID)) 228 return emitLibraryCall(*this, fd, e, 229 cgm.getBuiltinLibFunction(fd, builtinID)); 230 231 cgm.errorNYI(e->getSourceRange(), "unimplemented builtin call"); 232 return getUndefRValue(e->getType()); 233 } 234 235 /// Given a builtin id for a function like "__builtin_fabsf", return a Function* 236 /// for "fabsf". 237 cir::FuncOp CIRGenModule::getBuiltinLibFunction(const FunctionDecl *fd, 238 unsigned builtinID) { 239 assert(astContext.BuiltinInfo.isLibFunction(builtinID)); 240 241 // Get the name, skip over the __builtin_ prefix (if necessary). We may have 242 // to build this up so provide a small stack buffer to handle the vast 243 // majority of names. 244 llvm::SmallString<64> name; 245 246 assert(!cir::MissingFeatures::asmLabelAttr()); 247 name = astContext.BuiltinInfo.getName(builtinID).substr(10); 248 249 GlobalDecl d(fd); 250 mlir::Type type = convertType(fd->getType()); 251 return getOrCreateCIRFunction(name, type, d, /*forVTable=*/false); 252 } 253 254 mlir::Value CIRGenFunction::emitCheckedArgForAssume(const Expr *e) { 255 mlir::Value argValue = evaluateExprAsBool(e); 256 if (!sanOpts.has(SanitizerKind::Builtin)) 257 return argValue; 258 259 assert(!cir::MissingFeatures::sanitizers()); 260 cgm.errorNYI(e->getSourceRange(), 261 "emitCheckedArgForAssume: sanitizers are NYI"); 262 return {}; 263 } 264