439 lines · cpp
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-exception6//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 17using namespace clang;18using namespace CodeGen;19using namespace llvm;20 21/// Handle a SystemZ function in which the final argument is a pointer22/// to an int that receives the post-instruction CC value. At the LLVM level23/// this is represented as a function that returns a {result, cc} pair.24static 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 39Value *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 automatically73 // to target-specific LLVM intrinsics. The ones handled specially here can74 // be represented via standard LLVM IR, which is preferable to enable common75 // 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 standard219 // 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 allowed225 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 suppressed232 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 standard276 // 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 standard310 // 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_CC434 435 default:436 return nullptr;437 }438}439