xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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