@@ -42,6 +42,7 @@ enum class IntrinsicScalarFunctions : int64_t {
42
42
Exp2,
43
43
Expm1,
44
44
FMA,
45
+ FlipSign,
45
46
ListIndex,
46
47
Partition,
47
48
ListReverse,
@@ -95,6 +96,7 @@ inline std::string get_intrinsic_name(int x) {
95
96
INTRINSIC_NAME_CASE (Exp2)
96
97
INTRINSIC_NAME_CASE (Expm1)
97
98
INTRINSIC_NAME_CASE (FMA)
99
+ INTRINSIC_NAME_CASE (FlipSign)
98
100
INTRINSIC_NAME_CASE (ListIndex)
99
101
INTRINSIC_NAME_CASE (Partition)
100
102
INTRINSIC_NAME_CASE (ListReverse)
@@ -1343,6 +1345,86 @@ namespace FMA {
1343
1345
1344
1346
} // namespace FMA
1345
1347
1348
+ namespace FlipSign {
1349
+
1350
+ static inline void verify_args (const ASR::IntrinsicScalarFunction_t& x, diag::Diagnostics& diagnostics) {
1351
+ ASRUtils::require_impl (x.n_args == 2 ,
1352
+ " ASR Verify: Call to FlipSign must have exactly 2 arguments" ,
1353
+ x.base .base .loc , diagnostics);
1354
+ ASR::ttype_t *type1 = ASRUtils::expr_type (x.m_args [0 ]);
1355
+ ASR::ttype_t *type2 = ASRUtils::expr_type (x.m_args [1 ]);
1356
+ ASRUtils::require_impl ((is_integer (*type1) && is_real (*type2)),
1357
+ " ASR Verify: Arguments to FlipSign must be of int and real type respectively" ,
1358
+ x.base .base .loc , diagnostics);
1359
+ }
1360
+
1361
+ static ASR::expr_t *eval_FlipSign (Allocator &al, const Location &loc,
1362
+ ASR::ttype_t * t1, Vec<ASR::expr_t *> &args) {
1363
+ int a = ASR::down_cast<ASR::IntegerConstant_t>(args[0 ])->m_n ;
1364
+ double b = ASR::down_cast<ASR::RealConstant_t>(args[1 ])->m_r ;
1365
+ if (a % 2 == 1 ) b = -b;
1366
+ return make_ConstantWithType (make_RealConstant_t, b, t1, loc);
1367
+ }
1368
+
1369
+ static inline ASR::asr_t * create_FlipSign (Allocator& al, const Location& loc,
1370
+ Vec<ASR::expr_t *>& args,
1371
+ const std::function<void (const std::string &, const Location &)> err) {
1372
+ if (args.size () != 2 ) {
1373
+ err (" Intrinsic FlipSign function accepts exactly 2 arguments" , loc);
1374
+ }
1375
+ ASR::ttype_t *type1 = ASRUtils::expr_type (args[0 ]);
1376
+ ASR::ttype_t *type2 = ASRUtils::expr_type (args[1 ]);
1377
+ if (!ASRUtils::is_integer (*type1) || !ASRUtils::is_real (*type2)) {
1378
+ err (" Argument of the FlipSign function must be int and real respectively" ,
1379
+ args[0 ]->base .loc );
1380
+ }
1381
+ ASR::expr_t *m_value = nullptr ;
1382
+ if (all_args_evaluated (args)) {
1383
+ Vec<ASR::expr_t *> arg_values; arg_values.reserve (al, 2 );
1384
+ arg_values.push_back (al, expr_value (args[0 ]));
1385
+ arg_values.push_back (al, expr_value (args[1 ]));
1386
+ m_value = eval_FlipSign (al, loc, expr_type (args[1 ]), arg_values);
1387
+ }
1388
+ return ASR::make_IntrinsicScalarFunction_t (al, loc,
1389
+ static_cast <int64_t >(IntrinsicScalarFunctions::FlipSign),
1390
+ args.p , args.n , 0 , ASRUtils::expr_type (args[1 ]), m_value);
1391
+ }
1392
+
1393
+ static inline ASR::expr_t * instantiate_FlipSign (Allocator &al, const Location &loc,
1394
+ SymbolTable *scope, Vec<ASR::ttype_t *>& arg_types, ASR::ttype_t *return_type,
1395
+ Vec<ASR::call_arg_t >& new_args, int64_t /* overload_id*/ ) {
1396
+ declare_basic_variables (" _lcompilers_optimization_flipsign_" + type_to_str_python (arg_types[1 ]));
1397
+ fill_func_arg (" signal" , arg_types[0 ]);
1398
+ fill_func_arg (" variable" , arg_types[1 ]);
1399
+ auto result = declare (fn_name, return_type, ReturnVar);
1400
+ /*
1401
+ real(real32) function flipsigni32r32(signal, variable)
1402
+ integer(int32), intent(in) :: signal
1403
+ real(real32), intent(out) :: variable
1404
+ integer(int32) :: q
1405
+ q = signal/2
1406
+ flipsigni32r32 = variable
1407
+ if (signal - 2*q == 1 ) flipsigni32r32 = -variable
1408
+ end subroutine
1409
+ */
1410
+
1411
+ ASR::expr_t *two = i (2 , arg_types[0 ]);
1412
+ ASR::expr_t *q = iDiv (args[0 ], two);
1413
+ ASR::expr_t *cond = iSub (args[0 ], iMul (two, q));
1414
+ body.push_back (al, b.If (iEq (cond, i (1 , arg_types[0 ])), {
1415
+ b.Assignment (result, f32_neg (args[1 ], arg_types[1 ]))
1416
+ }, {
1417
+ b.Assignment (result, args[1 ])
1418
+ }));
1419
+
1420
+ ASR::symbol_t *f_sym = make_Function_t (fn_name, fn_symtab, dep, args,
1421
+ body, result, Source, Implementation, nullptr );
1422
+ scope->add_symbol (fn_name, f_sym);
1423
+ return b.Call (f_sym, new_args, return_type, nullptr );
1424
+ }
1425
+
1426
+ } // namespace FlipSign
1427
+
1346
1428
#define create_exp_macro (X, stdeval ) \
1347
1429
namespace X { \
1348
1430
static inline ASR::expr_t * eval_##X(Allocator &al, const Location &loc, \
@@ -2368,6 +2450,8 @@ namespace IntrinsicScalarFunctionRegistry {
2368
2450
{nullptr , &UnaryIntrinsicFunction::verify_args}},
2369
2451
{static_cast <int64_t >(IntrinsicScalarFunctions::FMA),
2370
2452
{&FMA::instantiate_FMA, &FMA::verify_args}},
2453
+ {static_cast <int64_t >(IntrinsicScalarFunctions::FlipSign),
2454
+ {&FlipSign::instantiate_FlipSign, &FMA::verify_args}},
2371
2455
{static_cast <int64_t >(IntrinsicScalarFunctions::Abs),
2372
2456
{&Abs::instantiate_Abs, &Abs::verify_args}},
2373
2457
{static_cast <int64_t >(IntrinsicScalarFunctions::Partition),
@@ -2456,6 +2540,8 @@ namespace IntrinsicScalarFunctionRegistry {
2456
2540
" exp2" },
2457
2541
{static_cast <int64_t >(IntrinsicScalarFunctions::FMA),
2458
2542
" fma" },
2543
+ {static_cast <int64_t >(IntrinsicScalarFunctions::FlipSign),
2544
+ " flipsign" },
2459
2545
{static_cast <int64_t >(IntrinsicScalarFunctions::Expm1),
2460
2546
" expm1" },
2461
2547
{static_cast <int64_t >(IntrinsicScalarFunctions::ListIndex),
0 commit comments