BOAST 1.3.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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