BOAST 1.3.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/BOAST.gemspec +1 -1
  3. data/LICENSE +13 -1
  4. data/README.md +62 -13
  5. data/lib/BOAST.rb +3 -1
  6. data/lib/BOAST/Language/ARMCPUID_by_name.rb +3752 -0
  7. data/lib/BOAST/Language/Algorithm.rb +4 -24
  8. data/lib/BOAST/Language/Architectures.rb +5 -0
  9. data/lib/BOAST/Language/Arithmetic.rb +38 -5
  10. data/lib/BOAST/Language/BOAST_OpenCL.rb +7 -8
  11. data/lib/BOAST/Language/Case.rb +10 -3
  12. data/lib/BOAST/Language/Config.rb +36 -12
  13. data/lib/BOAST/Language/ControlStructure.rb +7 -3
  14. data/lib/BOAST/Language/DataTypes.rb +6 -0
  15. data/lib/BOAST/Language/Expression.rb +26 -2
  16. data/lib/BOAST/Language/For.rb +59 -30
  17. data/lib/BOAST/Language/FuncCall.rb +9 -5
  18. data/lib/BOAST/Language/Functors.rb +1 -1
  19. data/lib/BOAST/Language/HighLevelOperators.rb +172 -0
  20. data/lib/BOAST/Language/If.rb +25 -9
  21. data/lib/BOAST/Language/Index.rb +5 -5
  22. data/lib/BOAST/Language/Intrinsics.rb +40 -27
  23. data/lib/BOAST/Language/OpenMP.rb +1 -0
  24. data/lib/BOAST/Language/Operators.rb +221 -34
  25. data/lib/BOAST/Language/Parens.rb +3 -2
  26. data/lib/BOAST/Language/Procedure.rb +18 -5
  27. data/lib/BOAST/Language/Slice.rb +176 -44
  28. data/lib/BOAST/Language/Variable.rb +99 -56
  29. data/lib/BOAST/Language/While.rb +18 -3
  30. data/lib/BOAST/Language/{CPUID_by_name.rb → X86CPUID_by_name.rb} +0 -0
  31. data/lib/BOAST/Optimization/Optimization.rb +2 -0
  32. data/lib/BOAST/Runtime/AffinityProbe.rb +7 -3
  33. data/lib/BOAST/Runtime/CKernel.rb +3 -0
  34. data/lib/BOAST/Runtime/CRuntime.rb +4 -0
  35. data/lib/BOAST/Runtime/CompiledRuntime.rb +404 -77
  36. data/lib/BOAST/Runtime/Compilers.rb +44 -18
  37. data/lib/BOAST/Runtime/Config.rb +9 -0
  38. data/lib/BOAST/Runtime/EnergyProbe.rb +19 -3
  39. data/lib/BOAST/Runtime/FFIRuntime.rb +23 -0
  40. data/lib/BOAST/Runtime/FORTRANRuntime.rb +1 -1
  41. data/lib/BOAST/Runtime/MAQAO.rb +29 -0
  42. data/lib/BOAST/Runtime/NonRegression.rb +64 -3
  43. data/lib/BOAST/Runtime/OpenCLRuntime.rb +16 -6
  44. data/lib/BOAST/Runtime/Probe.rb +21 -1
  45. metadata +5 -3
@@ -37,7 +37,7 @@ module BOAST
37
37
  end
38
38
 
39
39
  def to_s
40
- if get_replace_constants then
40
+ if get_replace_constants and @source.constant? then
41
41
  begin
42
42
  const = @source.constant
43
43
  indxs = @indexes.reverse
@@ -51,7 +51,7 @@ module BOAST
51
51
  const = const[ind]
52
52
  }
53
53
  return "#{const}#{@source.type.suffix}"
54
- rescue Exception => e
54
+ rescue Exception
55
55
  end
56
56
  end
57
57
  return to_s_fortran if lang == FORTRAN
@@ -73,13 +73,13 @@ module BOAST
73
73
  indexes_dup = []
74
74
  @source.dimension.each_with_index { |d,i|
75
75
  if d.size.nil? and get_array_start != 1 then
76
- indexes_dup.push( @indexes[i] - d.start + 1 )
76
+ indexes_dup.push( (@indexes[i] - d.start + 1).to_s )
77
77
  else
78
- indexes_dup.push( @indexes[i] )
78
+ indexes_dup.push( (@indexes[i]).to_s )
79
79
  end
80
80
  }
81
81
  s = ""
82
- s += "#{@source}(#{indexes_dup.join(", ")})"
82
+ s += "#{@source}(#{@source.vector? ? ":, " : "" }#{indexes_dup.join(", ")})"
83
83
  return s
84
84
  end
85
85
 
@@ -22,8 +22,10 @@ module BOAST
22
22
 
23
23
  MODELS = { "native" => native_flags }
24
24
  MODELS.update(X86architectures)
25
+ MODELS.update(ARMarchitectures)
25
26
  INSTRUCTIONS = {}
26
- INSTRUCTIONS.update(X86CPUID_by_name)
27
+ INSTRUCTIONS[X86] = X86CPUID_by_name
28
+ INSTRUCTIONS[ARM] = ARMCPUID_by_name
27
29
 
28
30
  class IntrinsicsError < Error
29
31
  end
@@ -39,21 +41,24 @@ module BOAST
39
41
  CONVERSIONS = Hash::new { |h, k| h[k] = Hash::new { |h2, k2| h2[k2] = {} } }
40
42
 
41
43
  def check_coverage
42
- ins = []
43
- INTRINSICS[X86].each { |i,v|
44
- if i == :CVT then
45
- v.each { |type1, h|
46
- h.each { |type2, instr|
44
+ instrs = [X86, ARM].collect { |ar|
45
+ ins = []
46
+ INTRINSICS[ar].each { |i,v|
47
+ if i == :CVT then
48
+ v.each { |type1, h|
49
+ h.each { |type2, instr|
50
+ ins.push instr.to_s
51
+ }
52
+ }
53
+ else
54
+ v.each { |type, instr|
47
55
  ins.push instr.to_s
48
56
  }
49
- }
50
- else
51
- v.each { |type, instr|
52
- ins.push instr.to_s
53
- }
54
- end
57
+ end
58
+ }
59
+ ins - INSTRUCTIONS[ar].keys
55
60
  }
56
- return ins - INSTRUCTIONS.keys
61
+ return instrs
57
62
  end
58
63
 
59
64
  module_function :check_coverage
@@ -65,9 +70,8 @@ module BOAST
65
70
  instruction = INTRINSICS[get_architecture][intr_symbol][type]
66
71
  end
67
72
  raise IntrinsicsError, "Unsupported operation #{intr_symbol} for #{type}#{type2 ? " and #{type2}" : ""} on #{get_architecture_name}!" unless instruction
68
- return instruction if get_architecture == ARM
69
73
  supported = false
70
- INSTRUCTIONS[instruction.to_s].each { |cpuid|
74
+ INSTRUCTIONS[get_architecture][instruction.to_s].each { |cpuid|
71
75
  if cpuid.kind_of?( Array ) then
72
76
  supported = true if (cpuid - MODELS[get_model.to_s]).empty?
73
77
  else
@@ -77,7 +81,7 @@ module BOAST
77
81
  # supported = (INSTRUCTIONS[instruction.to_s] & MODELS[get_model.to_s]).size > 0
78
82
  if not supported then
79
83
  required = ""
80
- INSTRUCTIONS[instruction.to_s].each { |cpuid|
84
+ INSTRUCTIONS[get_architecture][instruction.to_s].each { |cpuid|
81
85
  required += " or " if required != ""
82
86
  if cpuid.kind_of?( Array ) then
83
87
  required += "( #{cpuid.join(" and ")} )"
@@ -301,7 +305,13 @@ module BOAST
301
305
  [:MASK_LOAD, "mask_loadu"], [:MASK_STORE, "mask_storeu"],
302
306
  [:MASK_LOADA, "mask_load"], [:MASK_STOREA, "mask_store"],
303
307
  [:MASKZ_LOAD, "maskz_loadu"],
304
- [:MASKZ_LOADA, "maskz_load"]]
308
+ [:MASKZ_LOADA, "maskz_load"],
309
+ [:MAX, "max"], [:MIN, "min"],
310
+ [:SQRT, "sqrt"], [:EXP, "exp"], [:LOG, "log"], [:LOG10, "log10"],
311
+ [:SIN, "sin"], [:COS, "cos"], [:TAN, "tan"],
312
+ [:SINH, "sinh"], [:COSH, "cosh"], [:TANH, "tanh"],
313
+ [:ASIN, "asin"], [:ACOS, "acos"], [:ATAN, "atan"],
314
+ [:ASINH, "asinh"], [:ACOSH, "acosh"], [:ATANH, "atanh"]]
305
315
  instructions.push( [:MASKLOAD, "maskload"], [:MASKSTORE, "maskstore"] ) if vector_size < 512
306
316
  instructions.push( [:ADDSUB, "addsub"] ) if vector_size < 512
307
317
  instructions.each { |cl, ins|
@@ -364,14 +374,16 @@ module BOAST
364
374
 
365
375
  [64, 128].each { |vector_size|
366
376
  q = (vector_size == 128 ? "q" : "")
367
- [8, 16, 32, 64].each { |size|
377
+ scal_sizes = [8, 16, 32]
378
+ scal_sizes.push 64 if vector_size > 64
379
+ scal_sizes.each { |size|
368
380
  [:signed, :unsigned].each { |sign|
369
381
  vtype = vector_type_name( :int, size, vector_size, sign )
370
382
  type = type_name_ARM( :int, size, sign )
371
383
  instructions = [[:ADD, "add"], [:SUB, "sub"]]
372
384
  instructions.push( [:MUL, "mul"], [:FMADD, "mla"], [:FNMADD, "mls"] ) if size < 64
373
- instructions.push( [:LOAD, "ldl"], [:LOADA, "ldl"] )
374
- instructions.push( [:STORE, "stl"], [:STOREA, "stl"] )
385
+ instructions.push( [:LOAD, "ld1"], [:LOADA, "ld1"] )
386
+ instructions.push( [:STORE, "st1"], [:STOREA, "st1"] )
375
387
  instructions.each { |cl, ins|
376
388
  INTRINSICS[ARM][cl][vtype] = "v#{ins}#{q}_#{type}".to_sym
377
389
  }
@@ -383,13 +395,15 @@ module BOAST
383
395
  }
384
396
  }
385
397
  }
386
- [32, 64].each { |size|
398
+ scal_sizes = [32]
399
+ scal_sizes.push 64 if vector_size > 64
400
+ scal_sizes.each { |size|
387
401
  vtype = vector_type_name( :float, size, vector_size )
388
402
  type = type_name_ARM( :float, size )
389
403
  [[:ADD, "add"], [:SUB, "sub"], [:MUL, "mul"],
390
404
  [:FMADD, "mla"], [:FNMADD, "mls"],
391
- [:LOAD, "ldl"], [:LOADA, "ldl"],
392
- [:STORE, "stl"], [:STOREA, "stl"]].each { |cl, ins|
405
+ [:LOAD, "ld1"], [:LOADA, "ld1"],
406
+ [:STORE, "st1"], [:STOREA, "st1"]].each { |cl, ins|
393
407
  INTRINSICS[ARM][cl][vtype] = "v#{ins}#{q}_#{type}".to_sym
394
408
  }
395
409
  [[:SET1, "dup"]].each { |cl, ins|
@@ -439,10 +453,9 @@ module BOAST
439
453
  cvt_dgraph = RGL::DirectedAdjacencyGraph::new
440
454
  INTRINSICS[arch][:CVT].each { |dest, origs|
441
455
  origs.each { |orig, intrinsic|
442
- supported = true
443
- if arch == X86
444
- supported = false
445
- INSTRUCTIONS[intrinsic.to_s].each { |cpuid|
456
+ supported = false
457
+ if MODELS[get_model.to_s] then
458
+ INSTRUCTIONS[arch][intrinsic.to_s].each { |cpuid|
446
459
  if cpuid.kind_of?( Array ) then
447
460
  supported = true if (cpuid - MODELS[get_model.to_s]).empty?
448
461
  else
@@ -143,6 +143,7 @@ EOF
143
143
  end
144
144
 
145
145
  def initialize(options = {}, &block)
146
+ super()
146
147
  @openmp_clauses = options
147
148
  @block = block
148
149
  end
@@ -15,6 +15,11 @@ module BOAST
15
15
 
16
16
  def Operator.convert(arg, type)
17
17
  return "#{arg}" if get_vector_name(arg.type) == get_vector_name(type) or lang == CUDA
18
+
19
+ if arg.type.vector_length == 1 and type.vector_length > 1 then
20
+ return "#{Set::new( arg, Variable::new(:dummy, type.class, type.to_hash) )}"
21
+ end
22
+
18
23
  return "convert_#{type.decl}( #{arg} )" if lang == CL
19
24
 
20
25
  path = get_conversion_path(type, arg.type)
@@ -186,23 +191,6 @@ module BOAST
186
191
 
187
192
  end
188
193
 
189
- class Affectation < Operator
190
-
191
- def Affectation.string(arg1, arg2, return_type)
192
- if arg1.class == Variable and arg1.type.vector_length > 1 then
193
- return "#{arg1} = #{Load(arg2, arg1)}"
194
- elsif arg2.class == Variable and arg2.type.vector_length > 1 then
195
- return "#{Store(arg1, arg2, :store_type => return_type)}"
196
- end
197
- return basic_usage(arg1, arg2)
198
- end
199
-
200
- def Affectation.basic_usage(arg1, arg2)
201
- return "#{arg1} = #{arg2}"
202
- end
203
-
204
- end
205
-
206
194
  class Exponentiation < BasicBinaryOperator
207
195
 
208
196
  class << self
@@ -264,7 +252,7 @@ module BOAST
264
252
 
265
253
  end
266
254
 
267
- class Substraction < BasicBinaryOperator
255
+ class Subtraction < BasicBinaryOperator
268
256
 
269
257
  class << self
270
258
 
@@ -304,6 +292,38 @@ module BOAST
304
292
 
305
293
  end
306
294
 
295
+ class Min < BasicBinaryOperator
296
+
297
+ class << self
298
+
299
+ def intr_symbol
300
+ return :MIN
301
+ end
302
+
303
+ def basic_usage(arg1, arg2)
304
+ return "min( #{arg1}, #{arg2} )"
305
+ end
306
+
307
+ end
308
+
309
+ end
310
+
311
+ class Max < BasicBinaryOperator
312
+
313
+ class << self
314
+
315
+ def intr_symbol
316
+ return :MAX
317
+ end
318
+
319
+ def basic_usage(arg1, arg2)
320
+ return "max( #{arg1}, #{arg2} )"
321
+ end
322
+
323
+ end
324
+
325
+ end
326
+
307
327
  class Mask
308
328
  extend Functor
309
329
 
@@ -388,18 +408,32 @@ module BOAST
388
408
  begin
389
409
  instruction = intrinsics(:SET, @return_type.type)
390
410
  raise IntrinsicsError unless instruction
391
- return @return_type.copy("#{instruction}( #{@source.join(", ")} )", DISCARD_OPTIONS)
411
+ eff_srcs = @source.collect { |src|
412
+ eff_src = nil
413
+ eff_src = src.to_var if src.respond_to?(:to_var)
414
+ eff_src = src unless eff_src
415
+ eff_src
416
+ }
417
+ return @return_type.copy("#{instruction}( #{eff_srcs.join(", ")} )", DISCARD_OPTIONS)
392
418
  rescue IntrinsicsError
393
419
  instruction = intrinsics(:SET_LANE, @return_type.type)
394
420
  raise IntrinsicsError, "Missing instruction for SET_LANE on #{get_architecture_name}!" unless instruction
395
421
  s = Set(0, @return_type).to_s
396
422
  @source.each_with_index { |v,i|
397
- s = "#{instruction}( #{v}, #{s}, #{i} )"
423
+ eff_src = nil
424
+ eff_src = v.to_var if v.respond_to?(:to_var)
425
+ eff_src = v unless eff_src
426
+ s = "#{instruction}( #{eff_src}, #{s}, #{i} )"
398
427
  }
399
428
  return @return_type.copy(s, DISCARD_OPTIONS)
400
429
  end
401
430
  elsif @source.class != Variable or @source.type.vector_length == 1 then
402
- return @return_type.copy("(#{@return_type.type.decl})( #{@source} )", DISCARD_OPTIONS) if lang == CL
431
+ eff_src = nil
432
+ eff_src = @source.to_var if @source.respond_to?(:to_var)
433
+ eff_src = @source unless eff_src
434
+ if lang == CL then
435
+ return @return_type.copy("(#{@return_type.type.decl})( #{eff_src} )", DISCARD_OPTIONS) if lang == CL
436
+ end
403
437
  if (@source.is_a?(Numeric) and @source == 0) or (@source.class == Variable and @source.constant == 0) then
404
438
  begin
405
439
  instruction = intrinsics(:SETZERO, @return_type.type)
@@ -408,12 +442,73 @@ module BOAST
408
442
  end
409
443
  end
410
444
  instruction = intrinsics(:SET1, @return_type.type)
411
- return @return_type.copy("#{instruction}( #{@source} )", DISCARD_OPTIONS)
445
+ return @return_type.copy("#{instruction}( #{eff_src} )", DISCARD_OPTIONS)
412
446
  elsif @return_type.type != @source.type
413
447
  return @return_type.copy("#{Operator.convert(@source, @return_type.type)}", DISCARD_OPTIONS)
414
448
  end
449
+ elsif lang == FORTRAN and @return_type.type.vector_length > 1 then
450
+ if @source.kind_of?( Array ) then
451
+ raise OperatorError, "Invalid array length!" unless @source.length == @return_type.type.vector_length
452
+ return "(/#{@source.join(", ")}/)"
453
+ end
415
454
  end
416
- return @return_type.copy("#{@source}", DISCARD_OPTIONS)
455
+ eff_src = nil
456
+ eff_src = @source.to_var if @source.respond_to?(:to_var)
457
+ eff_src = @source unless eff_src
458
+ return @return_type.copy("#{eff_src}", DISCARD_OPTIONS)
459
+ end
460
+
461
+ def to_s
462
+ return to_var.to_s
463
+ end
464
+
465
+ def pr
466
+ s=""
467
+ s += indent
468
+ s += to_s
469
+ s += ";" if [C, CL, CUDA].include?( lang )
470
+ output.puts s
471
+ return self
472
+ end
473
+
474
+ end
475
+
476
+ # @!parse module Functors; functorize Affectation; end
477
+ class Affectation < Operator
478
+ extend Functor
479
+ include Intrinsics
480
+ include Arithmetic
481
+ include Inspectable
482
+ include PrivateStateAccessor
483
+
484
+ attr_reader :target
485
+ attr_reader :source
486
+ attr_reader :options
487
+
488
+ def initialize(target, source, options = {})
489
+ @target = target
490
+ @source = source
491
+ @options = options
492
+ end
493
+
494
+ def type
495
+ return target.to_var.type
496
+ end
497
+
498
+ def to_var
499
+ tar = @target
500
+ tar = @target.to_var if @target.respond_to?(:to_var)
501
+ src = @source
502
+ src = @source.to_var if @source.respond_to?(:to_var)
503
+ if tar.class == Variable and tar.type.vector_length > 1 then
504
+ return @target.copy("#{@target} = #{Load(@source, @target, @options)}", DISCARD_OPTIONS)
505
+ elsif src.class == Variable and src.type.vector_length > 1 then
506
+ r_t, _ = transition(tar, src, Affectation)
507
+ opts = @options.clone
508
+ opts[:store_type] = r_t
509
+ return @target.copy("#{Store(@target, @source, opts)}", DISCARD_OPTIONS)
510
+ end
511
+ return tar.copy("#{tar ? tar : @target} = #{src ? src : @source}", DISCARD_OPTIONS)
417
512
  end
418
513
 
419
514
  def to_s
@@ -431,6 +526,7 @@ module BOAST
431
526
 
432
527
  end
433
528
 
529
+
434
530
  # @!parse module Functors; functorize Load; end
435
531
  class Load < Operator
436
532
  extend Functor
@@ -460,10 +556,11 @@ module BOAST
460
556
  if @source.kind_of?(Array) then
461
557
  return Set(@source, @return_type).to_var
462
558
  elsif @source.class == Variable or @source.respond_to?(:to_var) then
463
- if @source.to_var.type == @return_type.type
464
- return @source.to_var
465
- elsif @source.to_var.type.vector_length == 1 then
466
- a2 = "#{@source}"
559
+ src_var = source.to_var
560
+ if src_var.type == @return_type.type then
561
+ return src_var
562
+ elsif src_var.type.vector_length == 1 then
563
+ a2 = "#{src_var}"
467
564
  if a2[0] != "*" then
468
565
  a2 = "&" + a2
469
566
  else
@@ -481,7 +578,7 @@ module BOAST
481
578
  sym += "Z" if @zero
482
579
  sym += "_"
483
580
  end
484
- if @source.alignment and @return_type.type.total_size and ( @source.alignment % @return_type.type.total_size ) == 0 then
581
+ if src_var.alignment and @return_type.type.total_size and ( src_var.alignment % @return_type.type.total_size ) == 0 then
485
582
  sym += "LOADA"
486
583
  else
487
584
  sym += "LOAD"
@@ -493,7 +590,17 @@ module BOAST
493
590
  end
494
591
  return @return_type.copy("#{instruction}( #{a2} )", DISCARD_OPTIONS)
495
592
  else
496
- return @return_type.copy("#{Operator.convert(@source, @return_type.type)}", DISCARD_OPTIONS)
593
+ return @return_type.copy("#{Operator.convert(src_var, @return_type.type)}", DISCARD_OPTIONS)
594
+ end
595
+ end
596
+ elsif lang == FORTRAN then
597
+ if @source.kind_of?(Array) then
598
+ return Set(@source, @return_type).to_var
599
+ elsif @source.class == Variable or @source.respond_to?(:to_var) then
600
+ if @source.to_var.type == @return_type.type then
601
+ return @source.to_var
602
+ elsif @source.kind_of?(Index) and @return_type.type.vector_length > 1 then
603
+ return @return_type.copy("#{Slice::new(@source.source, [@source.indexes[0], @source.indexes[0] + @return_type.type.vector_length - 1], *@source.indexes[1..-1])}", DISCARD_OPTIONS)
497
604
  end
498
605
  end
499
606
  end
@@ -601,6 +708,9 @@ module BOAST
601
708
  end
602
709
 
603
710
  def to_s
711
+ if @store_type.type == @dest.type then
712
+ return "#{@dest} = #{@source}"
713
+ end
604
714
  if lang == C or lang == CL then
605
715
  dst = "#{@dest}"
606
716
  if dst[0] != "*" then
@@ -626,8 +736,12 @@ module BOAST
626
736
  p_type = type if get_architecture == X86 and type.kind_of?(Int)
627
737
  return "#{instruction}( (#{p_type.decl} * ) #{dst}, (#{mask.value.type.decl})#{mask}, #{@source} )" if mask and not mask.full?
628
738
  return "#{instruction}( (#{p_type.decl} * ) #{dst}, #{@source} )"
739
+ elsif lang == FORTRAN
740
+ if @store_type.type.vector_length > 1 and @dest.kind_of?(Index) then
741
+ return "#{Slice::new(@dest.source, [@dest.indexes[0], @dest.indexes[0] + @store_type.type.vector_length - 1], *@dest.indexes[1..-1])} = #{@source}"
742
+ end
629
743
  end
630
- return Affectation.basic_usage(@dest, @source)
744
+ return "#{@dest} = #{@source}"
631
745
  end
632
746
 
633
747
  def pr
@@ -719,8 +833,7 @@ module BOAST
719
833
  @operand1 = a
720
834
  @operand2 = b
721
835
  @operand3 = c
722
- @return_type = nil
723
- @return_type = @operand3.to_var unless @return_type
836
+ @return_type = @operand3.to_var
724
837
  end
725
838
 
726
839
  def convert_operand(op)
@@ -790,8 +903,7 @@ module BOAST
790
903
  @operand1 = a
791
904
  @operand2 = b
792
905
  @operand3 = c
793
- @return_type = nil
794
- @return_type = @operand3.to_var unless @return_type
906
+ @return_type = @operand3.to_var
795
907
  end
796
908
 
797
909
  def convert_operand(op)
@@ -845,6 +957,81 @@ module BOAST
845
957
 
846
958
  end
847
959
 
960
+ class Modulo < Operator
961
+ extend Functor
962
+ include Arithmetic
963
+ include Inspectable
964
+ include PrivateStateAccessor
965
+ include TypeTransition
966
+
967
+ attr_reader :operand1
968
+ attr_reader :operand2
969
+ attr_reader :return_type
970
+
971
+ def initialize(x,y)
972
+ @operand1 = x
973
+ @operand2 = y
974
+ op1, op2 = op_to_var
975
+ @return_type, _ = transition(op1, op2, Modulo)
976
+ end
977
+
978
+ def to_s
979
+ return to_s_fortran if lang == FORTRAN
980
+ return to_s_c if [C, CL, CUDA].include?( lang )
981
+ end
982
+
983
+ def pr
984
+ s=""
985
+ s += indent
986
+ s += to_s
987
+ s += ";" if [C, CL, CUDA].include?( lang )
988
+ output.puts s
989
+ return self
990
+ end
991
+
992
+ def to_var
993
+ if @return_type then
994
+ return @return_type.copy( to_s, DISCARD_OPTIONS )
995
+ else
996
+ return Variable::new( to_s, get_default_type )
997
+ end
998
+ end
999
+
1000
+ private
1001
+
1002
+ def to_s_fortran
1003
+ op1, op2 = op_to_var
1004
+ if @return_type and @return_type.type.kind_of?(Real) and ( not op1.type.kind_of?(Real) or not op2.type.kind_of?(Real) ) then
1005
+ return "modulo(real(#{op1}, #{@return_type.type.size}), #{op2})" if not op1.type.kind_of?(Real)
1006
+ return "modulo(#{op1}, real(#{op2}, #{@return_type.type.size}))"
1007
+ else
1008
+ return "modulo(#{op1}, #{op2})"
1009
+ end
1010
+ end
1011
+
1012
+ def to_s_c
1013
+ op1, op2 = op_to_var
1014
+ if @return_type and @return_type.type.kind_of?(Real) then
1015
+ if @return_type.type.size <= 4 then
1016
+ return "((#{op1} < 0) ^ (#{op2} < 0) ? fmodf(#{op1}, #{op2}) + #{op2} : fmodf(#{op1}, #{op2}));"
1017
+ else
1018
+ return "((#{op1} < 0) ^ (#{op2} < 0) ? fmod(#{op1}, #{op2}) + #{op2} : fmod(#{op1}, #{op2}))"
1019
+ end
1020
+ else
1021
+ return "((#{op1} < 0) ^ (#{op2} < 0) ? (#{op1} % #{op2}) + #{op2} : #{op1} % #{op2})"
1022
+ end
1023
+ end
1024
+
1025
+ def op_to_var
1026
+ op1 = @operand1.respond_to?(:to_var) ? @operand1.to_var : @operand1
1027
+ op1 = @operand1 unless op1
1028
+ op2 = @operand2.respond_to?(:to_var) ? @operand2.to_var : @operand2
1029
+ op2 = @operand2 unless op2
1030
+ return [op1, op2]
1031
+ end
1032
+
1033
+ end
1034
+
848
1035
  # @!parse module Functors; functorize Ternary; end
849
1036
  class Ternary
850
1037
  extend Functor