1 //===------ SystemZ.cpp - Emit LLVM Code for builtins ---------------------===// 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 LLVM code. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "CodeGenFunction.h" 14 #include "clang/Basic/TargetBuiltins.h" 15 #include "llvm/IR/IntrinsicsS390.h" 16 17 using namespace clang; 18 using namespace CodeGen; 19 using namespace llvm; 20 21 /// Handle a SystemZ function in which the final argument is a pointer 22 /// to an int that receives the post-instruction CC value. At the LLVM level 23 /// this is represented as a function that returns a {result, cc} pair. 24 static Value *EmitSystemZIntrinsicWithCC(CodeGenFunction &CGF, 25 unsigned IntrinsicID, 26 const CallExpr *E) { 27 unsigned NumArgs = E->getNumArgs() - 1; 28 SmallVector<Value *, 8> Args(NumArgs); 29 for (unsigned I = 0; I < NumArgs; ++I) 30 Args[I] = CGF.EmitScalarExpr(E->getArg(I)); 31 Address CCPtr = CGF.EmitPointerWithAlignment(E->getArg(NumArgs)); 32 Function *F = CGF.CGM.getIntrinsic(IntrinsicID); 33 Value *Call = CGF.Builder.CreateCall(F, Args); 34 Value *CC = CGF.Builder.CreateExtractValue(Call, 1); 35 CGF.Builder.CreateStore(CC, CCPtr); 36 return CGF.Builder.CreateExtractValue(Call, 0); 37 } 38 39 Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID, 40 const CallExpr *E) { 41 switch (BuiltinID) { 42 case SystemZ::BI__builtin_tbegin: { 43 Value *TDB = EmitScalarExpr(E->getArg(0)); 44 Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff0c); 45 Function *F = CGM.getIntrinsic(Intrinsic::s390_tbegin); 46 return Builder.CreateCall(F, {TDB, Control}); 47 } 48 case SystemZ::BI__builtin_tbegin_nofloat: { 49 Value *TDB = EmitScalarExpr(E->getArg(0)); 50 Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff0c); 51 Function *F = CGM.getIntrinsic(Intrinsic::s390_tbegin_nofloat); 52 return Builder.CreateCall(F, {TDB, Control}); 53 } 54 case SystemZ::BI__builtin_tbeginc: { 55 Value *TDB = llvm::ConstantPointerNull::get(Int8PtrTy); 56 Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff08); 57 Function *F = CGM.getIntrinsic(Intrinsic::s390_tbeginc); 58 return Builder.CreateCall(F, {TDB, Control}); 59 } 60 case SystemZ::BI__builtin_tabort: { 61 Value *Data = EmitScalarExpr(E->getArg(0)); 62 Function *F = CGM.getIntrinsic(Intrinsic::s390_tabort); 63 return Builder.CreateCall(F, Builder.CreateSExt(Data, Int64Ty, "tabort")); 64 } 65 case SystemZ::BI__builtin_non_tx_store: { 66 Value *Address = EmitScalarExpr(E->getArg(0)); 67 Value *Data = EmitScalarExpr(E->getArg(1)); 68 Function *F = CGM.getIntrinsic(Intrinsic::s390_ntstg); 69 return Builder.CreateCall(F, {Data, Address}); 70 } 71 72 // Vector builtins. Note that most vector builtins are mapped automatically 73 // to target-specific LLVM intrinsics. The ones handled specially here can 74 // be represented via standard LLVM IR, which is preferable to enable common 75 // LLVM optimizations. 76 77 case SystemZ::BI__builtin_s390_vclzb: 78 case SystemZ::BI__builtin_s390_vclzh: 79 case SystemZ::BI__builtin_s390_vclzf: 80 case SystemZ::BI__builtin_s390_vclzg: 81 case SystemZ::BI__builtin_s390_vclzq: { 82 llvm::Type *ResultType = ConvertType(E->getType()); 83 Value *X = EmitScalarExpr(E->getArg(0)); 84 Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false); 85 Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ResultType); 86 return Builder.CreateCall(F, {X, Undef}); 87 } 88 89 case SystemZ::BI__builtin_s390_vctzb: 90 case SystemZ::BI__builtin_s390_vctzh: 91 case SystemZ::BI__builtin_s390_vctzf: 92 case SystemZ::BI__builtin_s390_vctzg: 93 case SystemZ::BI__builtin_s390_vctzq: { 94 llvm::Type *ResultType = ConvertType(E->getType()); 95 Value *X = EmitScalarExpr(E->getArg(0)); 96 Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false); 97 Function *F = CGM.getIntrinsic(Intrinsic::cttz, ResultType); 98 return Builder.CreateCall(F, {X, Undef}); 99 } 100 101 case SystemZ::BI__builtin_s390_verllb: 102 case SystemZ::BI__builtin_s390_verllh: 103 case SystemZ::BI__builtin_s390_verllf: 104 case SystemZ::BI__builtin_s390_verllg: { 105 llvm::Type *ResultType = ConvertType(E->getType()); 106 llvm::Value *Src = EmitScalarExpr(E->getArg(0)); 107 llvm::Value *Amt = EmitScalarExpr(E->getArg(1)); 108 // Splat scalar rotate amount to vector type. 109 unsigned NumElts = cast<llvm::FixedVectorType>(ResultType)->getNumElements(); 110 Amt = Builder.CreateIntCast(Amt, ResultType->getScalarType(), false); 111 Amt = Builder.CreateVectorSplat(NumElts, Amt); 112 Function *F = CGM.getIntrinsic(Intrinsic::fshl, ResultType); 113 return Builder.CreateCall(F, { Src, Src, Amt }); 114 } 115 116 case SystemZ::BI__builtin_s390_verllvb: 117 case SystemZ::BI__builtin_s390_verllvh: 118 case SystemZ::BI__builtin_s390_verllvf: 119 case SystemZ::BI__builtin_s390_verllvg: { 120 llvm::Type *ResultType = ConvertType(E->getType()); 121 llvm::Value *Src = EmitScalarExpr(E->getArg(0)); 122 llvm::Value *Amt = EmitScalarExpr(E->getArg(1)); 123 Function *F = CGM.getIntrinsic(Intrinsic::fshl, ResultType); 124 return Builder.CreateCall(F, { Src, Src, Amt }); 125 } 126 127 case SystemZ::BI__builtin_s390_vfsqsb: 128 case SystemZ::BI__builtin_s390_vfsqdb: { 129 llvm::Type *ResultType = ConvertType(E->getType()); 130 Value *X = EmitScalarExpr(E->getArg(0)); 131 if (Builder.getIsFPConstrained()) { 132 Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_sqrt, ResultType); 133 return Builder.CreateConstrainedFPCall(F, { X }); 134 } else { 135 Function *F = CGM.getIntrinsic(Intrinsic::sqrt, ResultType); 136 return Builder.CreateCall(F, X); 137 } 138 } 139 case SystemZ::BI__builtin_s390_vfmasb: 140 case SystemZ::BI__builtin_s390_vfmadb: { 141 llvm::Type *ResultType = ConvertType(E->getType()); 142 Value *X = EmitScalarExpr(E->getArg(0)); 143 Value *Y = EmitScalarExpr(E->getArg(1)); 144 Value *Z = EmitScalarExpr(E->getArg(2)); 145 if (Builder.getIsFPConstrained()) { 146 Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_fma, ResultType); 147 return Builder.CreateConstrainedFPCall(F, {X, Y, Z}); 148 } else { 149 Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType); 150 return Builder.CreateCall(F, {X, Y, Z}); 151 } 152 } 153 case SystemZ::BI__builtin_s390_vfmssb: 154 case SystemZ::BI__builtin_s390_vfmsdb: { 155 llvm::Type *ResultType = ConvertType(E->getType()); 156 Value *X = EmitScalarExpr(E->getArg(0)); 157 Value *Y = EmitScalarExpr(E->getArg(1)); 158 Value *Z = EmitScalarExpr(E->getArg(2)); 159 if (Builder.getIsFPConstrained()) { 160 Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_fma, ResultType); 161 return Builder.CreateConstrainedFPCall(F, {X, Y, Builder.CreateFNeg(Z, "neg")}); 162 } else { 163 Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType); 164 return Builder.CreateCall(F, {X, Y, Builder.CreateFNeg(Z, "neg")}); 165 } 166 } 167 case SystemZ::BI__builtin_s390_vfnmasb: 168 case SystemZ::BI__builtin_s390_vfnmadb: { 169 llvm::Type *ResultType = ConvertType(E->getType()); 170 Value *X = EmitScalarExpr(E->getArg(0)); 171 Value *Y = EmitScalarExpr(E->getArg(1)); 172 Value *Z = EmitScalarExpr(E->getArg(2)); 173 if (Builder.getIsFPConstrained()) { 174 Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_fma, ResultType); 175 return Builder.CreateFNeg(Builder.CreateConstrainedFPCall(F, {X, Y, Z}), "neg"); 176 } else { 177 Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType); 178 return Builder.CreateFNeg(Builder.CreateCall(F, {X, Y, Z}), "neg"); 179 } 180 } 181 case SystemZ::BI__builtin_s390_vfnmssb: 182 case SystemZ::BI__builtin_s390_vfnmsdb: { 183 llvm::Type *ResultType = ConvertType(E->getType()); 184 Value *X = EmitScalarExpr(E->getArg(0)); 185 Value *Y = EmitScalarExpr(E->getArg(1)); 186 Value *Z = EmitScalarExpr(E->getArg(2)); 187 if (Builder.getIsFPConstrained()) { 188 Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_fma, ResultType); 189 Value *NegZ = Builder.CreateFNeg(Z, "sub"); 190 return Builder.CreateFNeg(Builder.CreateConstrainedFPCall(F, {X, Y, NegZ})); 191 } else { 192 Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType); 193 Value *NegZ = Builder.CreateFNeg(Z, "neg"); 194 return Builder.CreateFNeg(Builder.CreateCall(F, {X, Y, NegZ})); 195 } 196 } 197 case SystemZ::BI__builtin_s390_vflpsb: 198 case SystemZ::BI__builtin_s390_vflpdb: { 199 llvm::Type *ResultType = ConvertType(E->getType()); 200 Value *X = EmitScalarExpr(E->getArg(0)); 201 Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType); 202 return Builder.CreateCall(F, X); 203 } 204 case SystemZ::BI__builtin_s390_vflnsb: 205 case SystemZ::BI__builtin_s390_vflndb: { 206 llvm::Type *ResultType = ConvertType(E->getType()); 207 Value *X = EmitScalarExpr(E->getArg(0)); 208 Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType); 209 return Builder.CreateFNeg(Builder.CreateCall(F, X), "neg"); 210 } 211 case SystemZ::BI__builtin_s390_vfisb: 212 case SystemZ::BI__builtin_s390_vfidb: { 213 llvm::Type *ResultType = ConvertType(E->getType()); 214 Value *X = EmitScalarExpr(E->getArg(0)); 215 // Constant-fold the M4 and M5 mask arguments. 216 llvm::APSInt M4 = *E->getArg(1)->getIntegerConstantExpr(getContext()); 217 llvm::APSInt M5 = *E->getArg(2)->getIntegerConstantExpr(getContext()); 218 // Check whether this instance can be represented via a LLVM standard 219 // intrinsic. We only support some combinations of M4 and M5. 220 Intrinsic::ID ID = Intrinsic::not_intrinsic; 221 Intrinsic::ID CI; 222 switch (M4.getZExtValue()) { 223 default: break; 224 case 0: // IEEE-inexact exception allowed 225 switch (M5.getZExtValue()) { 226 default: break; 227 case 0: ID = Intrinsic::rint; 228 CI = Intrinsic::experimental_constrained_rint; break; 229 } 230 break; 231 case 4: // IEEE-inexact exception suppressed 232 switch (M5.getZExtValue()) { 233 default: break; 234 case 0: ID = Intrinsic::nearbyint; 235 CI = Intrinsic::experimental_constrained_nearbyint; break; 236 case 1: ID = Intrinsic::round; 237 CI = Intrinsic::experimental_constrained_round; break; 238 case 4: ID = Intrinsic::roundeven; 239 CI = Intrinsic::experimental_constrained_roundeven; break; 240 case 5: ID = Intrinsic::trunc; 241 CI = Intrinsic::experimental_constrained_trunc; break; 242 case 6: ID = Intrinsic::ceil; 243 CI = Intrinsic::experimental_constrained_ceil; break; 244 case 7: ID = Intrinsic::floor; 245 CI = Intrinsic::experimental_constrained_floor; break; 246 } 247 break; 248 } 249 if (ID != Intrinsic::not_intrinsic) { 250 if (Builder.getIsFPConstrained()) { 251 Function *F = CGM.getIntrinsic(CI, ResultType); 252 return Builder.CreateConstrainedFPCall(F, X); 253 } else { 254 Function *F = CGM.getIntrinsic(ID, ResultType); 255 return Builder.CreateCall(F, X); 256 } 257 } 258 switch (BuiltinID) { // FIXME: constrained version? 259 case SystemZ::BI__builtin_s390_vfisb: ID = Intrinsic::s390_vfisb; break; 260 case SystemZ::BI__builtin_s390_vfidb: ID = Intrinsic::s390_vfidb; break; 261 default: llvm_unreachable("Unknown BuiltinID"); 262 } 263 Function *F = CGM.getIntrinsic(ID); 264 Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4); 265 Value *M5Value = llvm::ConstantInt::get(getLLVMContext(), M5); 266 return Builder.CreateCall(F, {X, M4Value, M5Value}); 267 } 268 case SystemZ::BI__builtin_s390_vfmaxsb: 269 case SystemZ::BI__builtin_s390_vfmaxdb: { 270 llvm::Type *ResultType = ConvertType(E->getType()); 271 Value *X = EmitScalarExpr(E->getArg(0)); 272 Value *Y = EmitScalarExpr(E->getArg(1)); 273 // Constant-fold the M4 mask argument. 274 llvm::APSInt M4 = *E->getArg(2)->getIntegerConstantExpr(getContext()); 275 // Check whether this instance can be represented via a LLVM standard 276 // intrinsic. We only support some values of M4. 277 Intrinsic::ID ID = Intrinsic::not_intrinsic; 278 Intrinsic::ID CI; 279 switch (M4.getZExtValue()) { 280 default: break; 281 case 4: ID = Intrinsic::maxnum; 282 CI = Intrinsic::experimental_constrained_maxnum; break; 283 } 284 if (ID != Intrinsic::not_intrinsic) { 285 if (Builder.getIsFPConstrained()) { 286 Function *F = CGM.getIntrinsic(CI, ResultType); 287 return Builder.CreateConstrainedFPCall(F, {X, Y}); 288 } else { 289 Function *F = CGM.getIntrinsic(ID, ResultType); 290 return Builder.CreateCall(F, {X, Y}); 291 } 292 } 293 switch (BuiltinID) { 294 case SystemZ::BI__builtin_s390_vfmaxsb: ID = Intrinsic::s390_vfmaxsb; break; 295 case SystemZ::BI__builtin_s390_vfmaxdb: ID = Intrinsic::s390_vfmaxdb; break; 296 default: llvm_unreachable("Unknown BuiltinID"); 297 } 298 Function *F = CGM.getIntrinsic(ID); 299 Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4); 300 return Builder.CreateCall(F, {X, Y, M4Value}); 301 } 302 case SystemZ::BI__builtin_s390_vfminsb: 303 case SystemZ::BI__builtin_s390_vfmindb: { 304 llvm::Type *ResultType = ConvertType(E->getType()); 305 Value *X = EmitScalarExpr(E->getArg(0)); 306 Value *Y = EmitScalarExpr(E->getArg(1)); 307 // Constant-fold the M4 mask argument. 308 llvm::APSInt M4 = *E->getArg(2)->getIntegerConstantExpr(getContext()); 309 // Check whether this instance can be represented via a LLVM standard 310 // intrinsic. We only support some values of M4. 311 Intrinsic::ID ID = Intrinsic::not_intrinsic; 312 Intrinsic::ID CI; 313 switch (M4.getZExtValue()) { 314 default: break; 315 case 4: ID = Intrinsic::minnum; 316 CI = Intrinsic::experimental_constrained_minnum; break; 317 } 318 if (ID != Intrinsic::not_intrinsic) { 319 if (Builder.getIsFPConstrained()) { 320 Function *F = CGM.getIntrinsic(CI, ResultType); 321 return Builder.CreateConstrainedFPCall(F, {X, Y}); 322 } else { 323 Function *F = CGM.getIntrinsic(ID, ResultType); 324 return Builder.CreateCall(F, {X, Y}); 325 } 326 } 327 switch (BuiltinID) { 328 case SystemZ::BI__builtin_s390_vfminsb: ID = Intrinsic::s390_vfminsb; break; 329 case SystemZ::BI__builtin_s390_vfmindb: ID = Intrinsic::s390_vfmindb; break; 330 default: llvm_unreachable("Unknown BuiltinID"); 331 } 332 Function *F = CGM.getIntrinsic(ID); 333 Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4); 334 return Builder.CreateCall(F, {X, Y, M4Value}); 335 } 336 337 case SystemZ::BI__builtin_s390_vlbrh: 338 case SystemZ::BI__builtin_s390_vlbrf: 339 case SystemZ::BI__builtin_s390_vlbrg: 340 case SystemZ::BI__builtin_s390_vlbrq: { 341 llvm::Type *ResultType = ConvertType(E->getType()); 342 Value *X = EmitScalarExpr(E->getArg(0)); 343 Function *F = CGM.getIntrinsic(Intrinsic::bswap, ResultType); 344 return Builder.CreateCall(F, X); 345 } 346 347 // Vector intrinsics that output the post-instruction CC value. 348 349 #define INTRINSIC_WITH_CC(NAME) \ 350 case SystemZ::BI__builtin_##NAME: \ 351 return EmitSystemZIntrinsicWithCC(*this, Intrinsic::NAME, E) 352 353 INTRINSIC_WITH_CC(s390_vpkshs); 354 INTRINSIC_WITH_CC(s390_vpksfs); 355 INTRINSIC_WITH_CC(s390_vpksgs); 356 357 INTRINSIC_WITH_CC(s390_vpklshs); 358 INTRINSIC_WITH_CC(s390_vpklsfs); 359 INTRINSIC_WITH_CC(s390_vpklsgs); 360 361 INTRINSIC_WITH_CC(s390_vceqbs); 362 INTRINSIC_WITH_CC(s390_vceqhs); 363 INTRINSIC_WITH_CC(s390_vceqfs); 364 INTRINSIC_WITH_CC(s390_vceqgs); 365 INTRINSIC_WITH_CC(s390_vceqqs); 366 367 INTRINSIC_WITH_CC(s390_vchbs); 368 INTRINSIC_WITH_CC(s390_vchhs); 369 INTRINSIC_WITH_CC(s390_vchfs); 370 INTRINSIC_WITH_CC(s390_vchgs); 371 INTRINSIC_WITH_CC(s390_vchqs); 372 373 INTRINSIC_WITH_CC(s390_vchlbs); 374 INTRINSIC_WITH_CC(s390_vchlhs); 375 INTRINSIC_WITH_CC(s390_vchlfs); 376 INTRINSIC_WITH_CC(s390_vchlgs); 377 INTRINSIC_WITH_CC(s390_vchlqs); 378 379 INTRINSIC_WITH_CC(s390_vfaebs); 380 INTRINSIC_WITH_CC(s390_vfaehs); 381 INTRINSIC_WITH_CC(s390_vfaefs); 382 383 INTRINSIC_WITH_CC(s390_vfaezbs); 384 INTRINSIC_WITH_CC(s390_vfaezhs); 385 INTRINSIC_WITH_CC(s390_vfaezfs); 386 387 INTRINSIC_WITH_CC(s390_vfeebs); 388 INTRINSIC_WITH_CC(s390_vfeehs); 389 INTRINSIC_WITH_CC(s390_vfeefs); 390 391 INTRINSIC_WITH_CC(s390_vfeezbs); 392 INTRINSIC_WITH_CC(s390_vfeezhs); 393 INTRINSIC_WITH_CC(s390_vfeezfs); 394 395 INTRINSIC_WITH_CC(s390_vfenebs); 396 INTRINSIC_WITH_CC(s390_vfenehs); 397 INTRINSIC_WITH_CC(s390_vfenefs); 398 399 INTRINSIC_WITH_CC(s390_vfenezbs); 400 INTRINSIC_WITH_CC(s390_vfenezhs); 401 INTRINSIC_WITH_CC(s390_vfenezfs); 402 403 INTRINSIC_WITH_CC(s390_vistrbs); 404 INTRINSIC_WITH_CC(s390_vistrhs); 405 INTRINSIC_WITH_CC(s390_vistrfs); 406 407 INTRINSIC_WITH_CC(s390_vstrcbs); 408 INTRINSIC_WITH_CC(s390_vstrchs); 409 INTRINSIC_WITH_CC(s390_vstrcfs); 410 411 INTRINSIC_WITH_CC(s390_vstrczbs); 412 INTRINSIC_WITH_CC(s390_vstrczhs); 413 INTRINSIC_WITH_CC(s390_vstrczfs); 414 415 INTRINSIC_WITH_CC(s390_vfcesbs); 416 INTRINSIC_WITH_CC(s390_vfcedbs); 417 INTRINSIC_WITH_CC(s390_vfchsbs); 418 INTRINSIC_WITH_CC(s390_vfchdbs); 419 INTRINSIC_WITH_CC(s390_vfchesbs); 420 INTRINSIC_WITH_CC(s390_vfchedbs); 421 422 INTRINSIC_WITH_CC(s390_vftcisb); 423 INTRINSIC_WITH_CC(s390_vftcidb); 424 425 INTRINSIC_WITH_CC(s390_vstrsb); 426 INTRINSIC_WITH_CC(s390_vstrsh); 427 INTRINSIC_WITH_CC(s390_vstrsf); 428 429 INTRINSIC_WITH_CC(s390_vstrszb); 430 INTRINSIC_WITH_CC(s390_vstrszh); 431 INTRINSIC_WITH_CC(s390_vstrszf); 432 433 #undef INTRINSIC_WITH_CC 434 435 default: 436 return nullptr; 437 } 438 } 439