Changeset 194003 in webkit


Ignore:
Timestamp:
Dec 11, 2015 10:10:07 PM (8 years ago)
Author:
commit-queue@webkit.org
Message:

[JSC] Add Floating Point Abs() to B3
https://bugs.webkit.org/show_bug.cgi?id=152176

Patch by Benjamin Poulain <bpoulain@apple.com> on 2015-12-11
Reviewed by Geoffrey Garen.

This patch adds an Abs() operation for floating point.

On x86, Abs() is implemented by masking the top bit
of the floating point value. On ARM64, there is a builtin
abs opcode.

To account for those differences, B3 use "Abs" as
the cannonical operation. When we are about to lower
to Air, Abs is extended on x86 to get a clean handling
of the mask constants.

This patch has one cool thing related to FTL.
If you do:

@1 = unboxDouble(@0)
@2 = abs(@1)
@3 = boxDouble(@2)

B3ReduceStrength completely eliminate the Double-Integer
conversion.

The strength reduction of Abs is aware that it can do a bit
mask over the bitcast used by unboxing.
If even works if you use floats by forcing fround: reduceDoubleToFloat()
elminiates the useless conversions, followed by ReduceStrength
that removes the switch from GP to FP.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • assembler/MacroAssemblerX86Common.h:

(JSC::MacroAssemblerX86Common::andDouble):
(JSC::MacroAssemblerX86Common::andFloat):

  • assembler/X86Assembler.h:

(JSC::X86Assembler::andps_rr):

  • b3/B3ConstDoubleValue.cpp:

(JSC::B3::ConstDoubleValue::bitAndConstant):
(JSC::B3::ConstDoubleValue::absConstant):

  • b3/B3ConstDoubleValue.h:
  • b3/B3ConstFloatValue.cpp:

(JSC::B3::ConstFloatValue::bitAndConstant):
(JSC::B3::ConstFloatValue::absConstant):

  • b3/B3ConstFloatValue.h:
  • b3/B3Generate.cpp:

(JSC::B3::generateToAir):

  • b3/B3LowerMacrosAfterOptimizations.cpp: Added.

(JSC::B3::lowerMacrosAfterOptimizations):

  • b3/B3LowerMacrosAfterOptimizations.h: Added.
  • b3/B3LowerToAir.cpp:

(JSC::B3::Air::LowerToAir::lower):

  • b3/B3Opcode.cpp:

(WTF::printInternal):

  • b3/B3Opcode.h:
  • b3/B3ReduceDoubleToFloat.cpp:
  • b3/B3ReduceStrength.cpp:
  • b3/B3Validate.cpp:
  • b3/B3Value.cpp:

(JSC::B3::Value::absConstant):
(JSC::B3::Value::effects):
(JSC::B3::Value::key):
(JSC::B3::Value::typeFor):

  • b3/B3Value.h:
  • b3/air/AirOpcode.opcodes:
  • b3/testb3.cpp:

(JSC::B3::bitAndDouble):
(JSC::B3::testBitAndArgDouble):
(JSC::B3::testBitAndArgsDouble):
(JSC::B3::testBitAndArgImmDouble):
(JSC::B3::testBitAndImmsDouble):
(JSC::B3::bitAndFloat):
(JSC::B3::testBitAndArgFloat):
(JSC::B3::testBitAndArgsFloat):
(JSC::B3::testBitAndArgImmFloat):
(JSC::B3::testBitAndImmsFloat):
(JSC::B3::testBitAndArgsFloatWithUselessDoubleConversion):
(JSC::B3::testAbsArg):
(JSC::B3::testAbsImm):
(JSC::B3::testAbsMem):
(JSC::B3::testAbsAbsArg):
(JSC::B3::testAbsBitwiseCastArg):
(JSC::B3::testBitwiseCastAbsBitwiseCastArg):
(JSC::B3::testAbsArgWithUselessDoubleConversion):
(JSC::B3::testAbsArgWithEffectfulDoubleConversion):
(JSC::B3::run):

  • ftl/FTLB3Output.h:

(JSC::FTL::Output::doubleAbs):

Location:
trunk/Source/JavaScriptCore
Files:
2 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r193989 r194003  
    115115    b3/B3InsertionSet.cpp
    116116    b3/B3LowerMacros.cpp
     117    b3/B3LowerMacrosAfterOptimizations.cpp
    117118    b3/B3LowerToAir.cpp
    118119    b3/B3MathExtras.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r193998 r194003  
     12015-12-11  Benjamin Poulain  <bpoulain@apple.com>
     2
     3        [JSC] Add Floating Point Abs() to B3
     4        https://bugs.webkit.org/show_bug.cgi?id=152176
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        This patch adds an Abs() operation for floating point.
     9
     10        On x86, Abs() is implemented by masking the top bit
     11        of the floating point value. On ARM64, there is a builtin
     12        abs opcode.
     13
     14        To account for those differences, B3 use "Abs" as
     15        the cannonical operation. When we are about to lower
     16        to Air, Abs is extended on x86 to get a clean handling
     17        of the mask constants.
     18
     19        This patch has one cool thing related to FTL.
     20        If you do:
     21           @1 = unboxDouble(@0)
     22           @2 = abs(@1)
     23           @3 = boxDouble(@2)
     24
     25        B3ReduceStrength completely eliminate the Double-Integer
     26        conversion.
     27
     28        The strength reduction of Abs is aware that it can do a bit
     29        mask over the bitcast used by unboxing.
     30        If even works if you use floats by forcing fround: reduceDoubleToFloat()
     31        elminiates the useless conversions, followed by ReduceStrength
     32        that removes the switch from GP to FP.
     33
     34        * CMakeLists.txt:
     35        * JavaScriptCore.xcodeproj/project.pbxproj:
     36        * assembler/MacroAssemblerX86Common.h:
     37        (JSC::MacroAssemblerX86Common::andDouble):
     38        (JSC::MacroAssemblerX86Common::andFloat):
     39        * assembler/X86Assembler.h:
     40        (JSC::X86Assembler::andps_rr):
     41        * b3/B3ConstDoubleValue.cpp:
     42        (JSC::B3::ConstDoubleValue::bitAndConstant):
     43        (JSC::B3::ConstDoubleValue::absConstant):
     44        * b3/B3ConstDoubleValue.h:
     45        * b3/B3ConstFloatValue.cpp:
     46        (JSC::B3::ConstFloatValue::bitAndConstant):
     47        (JSC::B3::ConstFloatValue::absConstant):
     48        * b3/B3ConstFloatValue.h:
     49        * b3/B3Generate.cpp:
     50        (JSC::B3::generateToAir):
     51        * b3/B3LowerMacrosAfterOptimizations.cpp: Added.
     52        (JSC::B3::lowerMacrosAfterOptimizations):
     53        * b3/B3LowerMacrosAfterOptimizations.h: Added.
     54        * b3/B3LowerToAir.cpp:
     55        (JSC::B3::Air::LowerToAir::lower):
     56        * b3/B3Opcode.cpp:
     57        (WTF::printInternal):
     58        * b3/B3Opcode.h:
     59        * b3/B3ReduceDoubleToFloat.cpp:
     60        * b3/B3ReduceStrength.cpp:
     61        * b3/B3Validate.cpp:
     62        * b3/B3Value.cpp:
     63        (JSC::B3::Value::absConstant):
     64        (JSC::B3::Value::effects):
     65        (JSC::B3::Value::key):
     66        (JSC::B3::Value::typeFor):
     67        * b3/B3Value.h:
     68        * b3/air/AirOpcode.opcodes:
     69        * b3/testb3.cpp:
     70        (JSC::B3::bitAndDouble):
     71        (JSC::B3::testBitAndArgDouble):
     72        (JSC::B3::testBitAndArgsDouble):
     73        (JSC::B3::testBitAndArgImmDouble):
     74        (JSC::B3::testBitAndImmsDouble):
     75        (JSC::B3::bitAndFloat):
     76        (JSC::B3::testBitAndArgFloat):
     77        (JSC::B3::testBitAndArgsFloat):
     78        (JSC::B3::testBitAndArgImmFloat):
     79        (JSC::B3::testBitAndImmsFloat):
     80        (JSC::B3::testBitAndArgsFloatWithUselessDoubleConversion):
     81        (JSC::B3::testAbsArg):
     82        (JSC::B3::testAbsImm):
     83        (JSC::B3::testAbsMem):
     84        (JSC::B3::testAbsAbsArg):
     85        (JSC::B3::testAbsBitwiseCastArg):
     86        (JSC::B3::testBitwiseCastAbsBitwiseCastArg):
     87        (JSC::B3::testAbsArgWithUselessDoubleConversion):
     88        (JSC::B3::testAbsArgWithEffectfulDoubleConversion):
     89        (JSC::B3::run):
     90        * ftl/FTLB3Output.h:
     91        (JSC::FTL::Output::doubleAbs):
     92
    1932015-12-11  Mark Lam  <mark.lam@apple.com>
    294
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r193989 r194003  
    11301130                41359CF30FDD89AD00206180 /* DateConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = D21202290AD4310C00ED79B6 /* DateConversion.h */; };
    11311131                41DEA1321B9F3163006D65DD /* BuiltinUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DEA1311B9F3154006D65DD /* BuiltinUtils.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1132                4319DA031C1BE40A001D260B /* B3LowerMacrosAfterOptimizations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4319DA011C1BE3C1001D260B /* B3LowerMacrosAfterOptimizations.cpp */; };
     1133                4319DA041C1BE40D001D260B /* B3LowerMacrosAfterOptimizations.h in Headers */ = {isa = PBXBuildFile; fileRef = 4319DA021C1BE3C1001D260B /* B3LowerMacrosAfterOptimizations.h */; };
    11321134                4340A4841A9051AF00D73CCA /* MathCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4340A4821A9051AF00D73CCA /* MathCommon.cpp */; };
    11331135                4340A4851A9051AF00D73CCA /* MathCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 4340A4831A9051AF00D73CCA /* MathCommon.h */; };
     
    32083210                371D842C17C98B6E00ECF994 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
    32093211                41DEA1311B9F3154006D65DD /* BuiltinUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BuiltinUtils.h; sourceTree = "<group>"; };
     3212                4319DA011C1BE3C1001D260B /* B3LowerMacrosAfterOptimizations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3LowerMacrosAfterOptimizations.cpp; path = b3/B3LowerMacrosAfterOptimizations.cpp; sourceTree = "<group>"; };
     3213                4319DA021C1BE3C1001D260B /* B3LowerMacrosAfterOptimizations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3LowerMacrosAfterOptimizations.h; path = b3/B3LowerMacrosAfterOptimizations.h; sourceTree = "<group>"; };
    32103214                4340A4821A9051AF00D73CCA /* MathCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathCommon.cpp; sourceTree = "<group>"; };
    32113215                4340A4831A9051AF00D73CCA /* MathCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MathCommon.h; sourceTree = "<group>"; };
     
    46204624                                0F338E021BF0276C0013C88F /* B3DataSection.h */,
    46214625                                0F33FCFA1C1625BE00323F67 /* B3Dominators.h */,
    4622                                 43422A641C16221E00E2EB98 /* B3ReduceDoubleToFloat.cpp */,
    4623                                 43422A651C16221E00E2EB98 /* B3ReduceDoubleToFloat.h */,
    46244626                                0FEC85C41BE16F5A0080FF74 /* B3Effects.cpp */,
    46254627                                0FEC85BE1BE167A00080FF74 /* B3Effects.h */,
     
    46394641                                0F338E191BF286EA0013C88F /* B3LowerMacros.cpp */,
    46404642                                0F338E1A1BF286EA0013C88F /* B3LowerMacros.h */,
     4643                                4319DA011C1BE3C1001D260B /* B3LowerMacrosAfterOptimizations.cpp */,
     4644                                4319DA021C1BE3C1001D260B /* B3LowerMacrosAfterOptimizations.h */,
    46414645                                0FEC84D31BDACDAC0080FF74 /* B3LowerToAir.cpp */,
    46424646                                0FEC84D41BDACDAC0080FF74 /* B3LowerToAir.h */,
     
    46654669                                0FEC84E21BDACDAC0080FF74 /* B3Procedure.h */,
    46664670                                0FEC84E31BDACDAC0080FF74 /* B3ProcedureInlines.h */,
     4671                                43422A641C16221E00E2EB98 /* B3ReduceDoubleToFloat.cpp */,
     4672                                43422A651C16221E00E2EB98 /* B3ReduceDoubleToFloat.h */,
    46674673                                0FEC85B71BE1462F0080FF74 /* B3ReduceStrength.cpp */,
    46684674                                0FEC85B81BE1462F0080FF74 /* B3ReduceStrength.h */,
     
    77317737                                FE3A06B21C10CB8900390FDD /* JITBitAndGenerator.h in Headers */,
    77327738                                0FD3E40E1B618B6600C80E1E /* PropertyCondition.h in Headers */,
     7739                                4319DA041C1BE40D001D260B /* B3LowerMacrosAfterOptimizations.h in Headers */,
    77337740                                A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */,
    77347741                                BC95437D0EBA70FD0072B6D3 /* PropertyMapHashTable.h in Headers */,
     
    87898796                                0F25F1B3181635F300522F39 /* FTLSlowPathCallKey.cpp in Sources */,
    87908797                                0F9D339A1803ADB70073C2BC /* FTLStackMaps.cpp in Sources */,
     8798                                4319DA031C1BE40A001D260B /* B3LowerMacrosAfterOptimizations.cpp in Sources */,
    87918799                                0FEA0A161706BB9000BB722C /* FTLState.cpp in Sources */,
    87928800                                0F235BE117178E1C00690C7F /* FTLThunks.cpp in Sources */,
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r193804 r194003  
    10121012        ASSERT(isSSE2Present());
    10131013        m_assembler.mulss_mr(src.offset, src.base, dest);
     1014    }
     1015
     1016    void andDouble(FPRegisterID src, FPRegisterID dst)
     1017    {
     1018        // ANDPS is defined on 128bits and is shorter than ANDPD.
     1019        m_assembler.andps_rr(src, dst);
     1020    }
     1021
     1022    void andFloat(FPRegisterID src, FPRegisterID dst)
     1023    {
     1024        m_assembler.andps_rr(src, dst);
    10141025    }
    10151026
  • trunk/Source/JavaScriptCore/assembler/X86Assembler.h

    r193804 r194003  
    274274        OP2_MOVMSKPD_VdEd   = 0x50,
    275275        OP2_SQRTSD_VsdWsd   = 0x51,
     276        OP2_ANDPS_VpdWpd    = 0x54,
    276277        OP2_ANDNPD_VpdWpd   = 0x55,
    277278        OP2_XORPD_VpdWpd    = 0x57,
     
    22822283        m_formatter.prefix(PRE_SSE_F3);
    22832284        m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, (RegisterID)dst, base, offset);
     2285    }
     2286
     2287    void andps_rr(XMMRegisterID src, XMMRegisterID dst)
     2288    {
     2289        m_formatter.twoByteOp(OP2_ANDPS_VpdWpd, (RegisterID)dst, (RegisterID)src);
    22842290    }
    22852291
  • trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp

    r193933 r194003  
    7070}
    7171
     72Value* ConstDoubleValue::bitAndConstant(Procedure& proc, const Value* other) const
     73{
     74    if (!other->hasDouble())
     75        return nullptr;
     76    double result = bitwise_cast<double>(bitwise_cast<uint64_t>(m_value) & bitwise_cast<uint64_t>(other->asDouble()));
     77    return proc.add<ConstDoubleValue>(origin(), result);
     78}
     79
    7280Value* ConstDoubleValue::bitwiseCastConstant(Procedure& proc) const
    7381{
     
    7886{
    7987    return proc.add<ConstFloatValue>(origin(), static_cast<float>(m_value));
     88}
     89
     90Value* ConstDoubleValue::absConstant(Procedure& proc) const
     91{
     92    return proc.add<ConstDoubleValue>(origin(), fabs(m_value));
    8093}
    8194
  • trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.h

    r193933 r194003  
    4848    Value* modConstant(Procedure&, const Value* other) const override;
    4949    Value* mulConstant(Procedure&, const Value* other) const override;
     50    Value* bitAndConstant(Procedure&, const Value* other) const override;
    5051    Value* bitwiseCastConstant(Procedure&) const override;
    5152    Value* doubleToFloatConstant(Procedure&) const override;
     53    Value* absConstant(Procedure&) const override;
    5254    Value* sqrtConstant(Procedure&) const override;
    5355
  • trunk/Source/JavaScriptCore/b3/B3ConstFloatValue.cpp

    r193683 r194003  
    7070}
    7171
     72Value* ConstFloatValue::bitAndConstant(Procedure& proc, const Value* other) const
     73{
     74    if (!other->hasFloat())
     75        return nullptr;
     76    float result = bitwise_cast<float>(bitwise_cast<uint32_t>(m_value) & bitwise_cast<uint32_t>(other->asFloat()));
     77    return proc.add<ConstFloatValue>(origin(), result);
     78}
     79
    7280Value* ConstFloatValue::bitwiseCastConstant(Procedure& proc) const
    7381{
     
    7886{
    7987    return proc.add<ConstDoubleValue>(origin(), static_cast<double>(m_value));
     88}
     89
     90Value* ConstFloatValue::absConstant(Procedure& proc) const
     91{
     92    return proc.add<ConstFloatValue>(origin(), static_cast<float>(fabs(m_value)));
    8093}
    8194
  • trunk/Source/JavaScriptCore/b3/B3ConstFloatValue.h

    r193683 r194003  
    4747    Value* divConstant(Procedure&, const Value* other) const override;
    4848    Value* mulConstant(Procedure&, const Value* other) const override;
     49    Value* bitAndConstant(Procedure&, const Value* other) const override;
    4950    Value* bitwiseCastConstant(Procedure&) const override;
    5051    Value* floatToDoubleConstant(Procedure&) const override;
     52    Value* absConstant(Procedure&) const override;
    5153    Value* sqrtConstant(Procedure&) const override;
    5254
  • trunk/Source/JavaScriptCore/b3/B3Generate.cpp

    r193683 r194003  
    3434#include "B3Common.h"
    3535#include "B3LowerMacros.h"
     36#include "B3LowerMacrosAfterOptimizations.h"
    3637#include "B3LowerToAir.h"
    3738#include "B3MoveConstants.h"
     
    8384    }
    8485
     86    lowerMacrosAfterOptimizations(procedure);
     87
    8588    moveConstants(procedure);
    8689
  • trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp

    r193941 r194003  
    14601460
    14611461        case BitAnd: {
    1462             appendBinOp<And32, And64, Commutative>(
     1462            appendBinOp<And32, And64, AndDouble, AndFloat, Commutative>(
    14631463                m_value->child(0), m_value->child(1));
    14641464            return;
  • trunk/Source/JavaScriptCore/b3/B3Opcode.cpp

    r193933 r194003  
    147147        out.print("Clz");
    148148        return;
     149    case Abs:
     150        out.print("Abs");
     151        return;
    149152    case Sqrt:
    150153        out.print("Sqrt");
  • trunk/Source/JavaScriptCore/b3/B3Opcode.h

    r193933 r194003  
    8585    Clz, // Count leading zeros.
    8686
    87     // Double math.
     87    // Floating point math.
     88    Abs,
    8889    Sqrt,
    8990
  • trunk/Source/JavaScriptCore/b3/B3ReduceDoubleToFloat.cpp

    r193683 r194003  
    4949        }
    5050        break;
     51    case Abs:
    5152    case Sqrt:
    5253        if (candidate->child(0)->opcode() == FloatToDouble) {
  • trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp

    r193993 r194003  
    506506            break;
    507507
     508        case Abs:
     509            // Turn this: Abs(constant)
     510            // Into this: fabs<value->type()>(constant)
     511            if (Value* constant = m_value->child(0)->absConstant(m_proc)) {
     512                replaceWithNewValue(constant);
     513                break;
     514            }
     515
     516            // Turn this: Abs(Abs(value))
     517            // Into this: Abs(value)
     518            if (m_value->child(0)->opcode() == Abs) {
     519                m_value->replaceWithIdentity(m_value->child(0));
     520                break;
     521            }
     522
     523            // Turn this: Abs(BitwiseCast(value))
     524            // Into this: BitwiseCast(And(value, mask-top-bit))
     525            if (m_value->child(0)->opcode() == BitwiseCast) {
     526                Value* mask;
     527                if (m_value->type() == Double)
     528                    mask = m_insertionSet.insert<Const64Value>(m_index, m_value->origin(), ~(1l << 63));
     529                else
     530                    mask = m_insertionSet.insert<Const32Value>(m_index, m_value->origin(), ~(1l << 31));
     531
     532                Value* bitAnd = m_insertionSet.insert<Value>(m_index, BitAnd, m_value->origin(),
     533                    m_value->child(0)->child(0),
     534                    mask);
     535                Value* cast = m_insertionSet.insert<Value>(m_index, BitwiseCast, m_value->origin(), bitAnd);
     536                m_value->replaceWithIdentity(cast);
     537                break;
     538            }
     539            break;
     540
    508541        case Sqrt:
    509542            // Turn this: Sqrt(constant)
  • trunk/Source/JavaScriptCore/b3/B3Validate.cpp

    r193943 r194003  
    155155            case Div:
    156156            case Mod:
     157            case BitAnd:
    157158                VALIDATE(value->numChildren() == 2, ("At ", *value));
    158159                VALIDATE(value->type() == value->child(0)->type(), ("At ", *value));
     
    162163            case ChillDiv:
    163164            case ChillMod:
    164             case BitAnd:
    165165            case BitOr:
    166166            case BitXor:
     
    210210                VALIDATE(value->type() == Int32, ("At ", *value));
    211211                break;
     212            case Abs:
    212213            case Sqrt:
    213214                VALIDATE(value->numChildren() == 1, ("At ", *value));
  • trunk/Source/JavaScriptCore/b3/B3Value.cpp

    r193987 r194003  
    218218
    219219Value* Value::floatToDoubleConstant(Procedure&) const
     220{
     221    return nullptr;
     222}
     223
     224Value* Value::absConstant(Procedure&) const
    220225{
    221226    return nullptr;
     
    358363    case ZShr:
    359364    case Clz:
     365    case Abs:
    360366    case Sqrt:
    361367    case BitwiseCast:
     
    434440        return ValueKey(opcode(), type());
    435441    case Identity:
     442    case Abs:
    436443    case Sqrt:
    437444    case SExt8:
     
    540547    case ZShr:
    541548    case Clz:
     549    case Abs:
    542550    case Sqrt:
    543551    case CheckAdd:
  • trunk/Source/JavaScriptCore/b3/B3Value.h

    r193943 r194003  
    132132    virtual Value* doubleToFloatConstant(Procedure&) const;
    133133    virtual Value* floatToDoubleConstant(Procedure&) const;
     134    virtual Value* absConstant(Procedure&) const;
    134135    virtual Value* sqrtConstant(Procedure&) const;
    135136
  • trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes

    r193804 r194003  
    171171    Imm, Tmp
    172172
     173AndDouble U:F, UD:F
     174    Tmp, Tmp
     175
     176AndFloat U:F, UD:F
     177    Tmp, Tmp
     178
    173179Lshift32 U:G, UD:G
    174180    Tmp*, Tmp
  • trunk/Source/JavaScriptCore/b3/testb3.cpp

    r193989 r194003  
    19431943}
    19441944
     1945double bitAndDouble(double a, double b)
     1946{
     1947    return bitwise_cast<double>(bitwise_cast<uint64_t>(a) & bitwise_cast<uint64_t>(b));
     1948}
     1949
     1950void testBitAndArgDouble(double a)
     1951{
     1952    Procedure proc;
     1953    BasicBlock* root = proc.addBlock();
     1954    Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
     1955    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argument, argument);
     1956    root->appendNew<ControlValue>(proc, Return, Origin(), result);
     1957
     1958    CHECK(isIdentical(compileAndRun<double>(proc, a), bitAndDouble(a, a)));
     1959}
     1960
     1961void testBitAndArgsDouble(double a, double b)
     1962{
     1963    Procedure proc;
     1964    BasicBlock* root = proc.addBlock();
     1965    Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
     1966    Value* argumentB = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
     1967    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
     1968    root->appendNew<ControlValue>(proc, Return, Origin(), result);
     1969
     1970    CHECK(isIdentical(compileAndRun<double>(proc, a, b), bitAndDouble(a, b)));
     1971}
     1972
     1973void testBitAndArgImmDouble(double a, double b)
     1974{
     1975    Procedure proc;
     1976    BasicBlock* root = proc.addBlock();
     1977    Value* argumentA = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
     1978    Value* argumentB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
     1979    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
     1980    root->appendNew<ControlValue>(proc, Return, Origin(), result);
     1981
     1982    CHECK(isIdentical(compileAndRun<double>(proc, a, b), bitAndDouble(a, b)));
     1983}
     1984
     1985void testBitAndImmsDouble(double a, double b)
     1986{
     1987    Procedure proc;
     1988    BasicBlock* root = proc.addBlock();
     1989    Value* argumentA = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
     1990    Value* argumentB = root->appendNew<ConstDoubleValue>(proc, Origin(), b);
     1991    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
     1992    root->appendNew<ControlValue>(proc, Return, Origin(), result);
     1993
     1994    CHECK(isIdentical(compileAndRun<double>(proc), bitAndDouble(a, b)));
     1995}
     1996
     1997float bitAndFloat(float a, float b)
     1998{
     1999    return bitwise_cast<float>(bitwise_cast<uint32_t>(a) & bitwise_cast<uint32_t>(b));
     2000}
     2001
     2002void testBitAndArgFloat(float a)
     2003{
     2004    Procedure proc;
     2005    BasicBlock* root = proc.addBlock();
     2006    Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(),
     2007        root->appendNew<Value>(proc, Trunc, Origin(),
     2008            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
     2009    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argument, argument);
     2010    root->appendNew<ControlValue>(proc, Return, Origin(), result);
     2011
     2012    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), bitAndFloat(a, a)));
     2013}
     2014
     2015void testBitAndArgsFloat(float a, float b)
     2016{
     2017    Procedure proc;
     2018    BasicBlock* root = proc.addBlock();
     2019    Value* argumentA = root->appendNew<Value>(proc, BitwiseCast, Origin(),
     2020        root->appendNew<Value>(proc, Trunc, Origin(),
     2021            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
     2022    Value* argumentB = root->appendNew<Value>(proc, BitwiseCast, Origin(),
     2023        root->appendNew<Value>(proc, Trunc, Origin(),
     2024            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
     2025    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
     2026    root->appendNew<ControlValue>(proc, Return, Origin(), result);
     2027
     2028    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitAndFloat(a, b)));
     2029}
     2030
     2031void testBitAndArgImmFloat(float a, float b)
     2032{
     2033    Procedure proc;
     2034    BasicBlock* root = proc.addBlock();
     2035    Value* argumentA = root->appendNew<Value>(proc, BitwiseCast, Origin(),
     2036        root->appendNew<Value>(proc, Trunc, Origin(),
     2037            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
     2038    Value* argumentB = root->appendNew<ConstFloatValue>(proc, Origin(), b);
     2039    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
     2040    root->appendNew<ControlValue>(proc, Return, Origin(), result);
     2041
     2042    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), bitAndFloat(a, b)));
     2043}
     2044
     2045void testBitAndImmsFloat(float a, float b)
     2046{
     2047    Procedure proc;
     2048    BasicBlock* root = proc.addBlock();
     2049    Value* argumentA = root->appendNew<ConstFloatValue>(proc, Origin(), a);
     2050    Value* argumentB = root->appendNew<ConstFloatValue>(proc, Origin(), b);
     2051    Value* result = root->appendNew<Value>(proc, BitAnd, Origin(), argumentA, argumentB);
     2052    root->appendNew<ControlValue>(proc, Return, Origin(), result);
     2053
     2054    CHECK(isIdentical(compileAndRun<float>(proc), bitAndFloat(a, b)));
     2055}
     2056
     2057void testBitAndArgsFloatWithUselessDoubleConversion(float a, float b)
     2058{
     2059    Procedure proc;
     2060    BasicBlock* root = proc.addBlock();
     2061    Value* argumentA = root->appendNew<Value>(proc, BitwiseCast, Origin(),
     2062        root->appendNew<Value>(proc, Trunc, Origin(),
     2063            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
     2064    Value* argumentB = root->appendNew<Value>(proc, BitwiseCast, Origin(),
     2065        root->appendNew<Value>(proc, Trunc, Origin(),
     2066            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
     2067    Value* argumentAasDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), argumentA);
     2068    Value* argumentBasDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), argumentB);
     2069    Value* doubleResult = root->appendNew<Value>(proc, BitAnd, Origin(), argumentAasDouble, argumentBasDouble);
     2070    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), doubleResult);
     2071    root->appendNew<ControlValue>(proc, Return, Origin(), floatResult);
     2072
     2073    double doubleA = a;
     2074    double doubleB = b;
     2075    float expected = static_cast<float>(bitAndDouble(doubleA, doubleB));
     2076    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b)), expected));
     2077}
     2078
    19452079void testBitOrArgs(int64_t a, int64_t b)
    19462080{
     
    28963030    root->appendNew<ControlValue>(proc, Return, Origin(), clzValue);
    28973031    CHECK(compileAndRun<unsigned>(proc, &a) == countLeadingZero(a));
     3032}
     3033
     3034void testAbsArg(double a)
     3035{
     3036    Procedure proc;
     3037    BasicBlock* root = proc.addBlock();
     3038    root->appendNew<ControlValue>(
     3039        proc, Return, Origin(),
     3040        root->appendNew<Value>(
     3041            proc, Abs, Origin(),
     3042                root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)));
     3043
     3044    CHECK(isIdentical(compileAndRun<double>(proc, a), fabs(a)));
     3045}
     3046
     3047void testAbsImm(double a)
     3048{
     3049    Procedure proc;
     3050    BasicBlock* root = proc.addBlock();
     3051    Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
     3052    root->appendNew<ControlValue>(
     3053        proc, Return, Origin(),
     3054        root->appendNew<Value>(proc, Abs, Origin(), argument));
     3055
     3056    CHECK(isIdentical(compileAndRun<double>(proc), fabs(a)));
     3057}
     3058
     3059void testAbsMem(double a)
     3060{
     3061    Procedure proc;
     3062    BasicBlock* root = proc.addBlock();
     3063    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     3064    MemoryValue* loadDouble = root->appendNew<MemoryValue>(proc, Load, Double, Origin(), address);
     3065    root->appendNew<ControlValue>(
     3066        proc, Return, Origin(),
     3067        root->appendNew<Value>(proc, Abs, Origin(), loadDouble));
     3068
     3069    CHECK(isIdentical(compileAndRun<double>(proc, &a), fabs(a)));
     3070}
     3071
     3072void testAbsAbsArg(double a)
     3073{
     3074    Procedure proc;
     3075    BasicBlock* root = proc.addBlock();
     3076    Value* firstAbs = root->appendNew<Value>(proc, Abs, Origin(),
     3077        root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
     3078    Value* secondAbs = root->appendNew<Value>(proc, Abs, Origin(), firstAbs);
     3079    root->appendNew<ControlValue>(proc, Return, Origin(), secondAbs);
     3080
     3081    CHECK(isIdentical(compileAndRun<double>(proc, a), fabs(a)));
     3082}
     3083
     3084void testAbsBitwiseCastArg(double a)
     3085{
     3086    Procedure proc;
     3087    BasicBlock* root = proc.addBlock();
     3088    Value* argumentAsInt64 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     3089    Value* argumentAsDouble = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentAsInt64);
     3090    Value* absValue = root->appendNew<Value>(proc, Abs, Origin(), argumentAsDouble);
     3091    root->appendNew<ControlValue>(proc, Return, Origin(), absValue);
     3092
     3093    CHECK(isIdentical(compileAndRun<double>(proc, bitwise_cast<int64_t>(a)), fabs(a)));
     3094}
     3095
     3096void testBitwiseCastAbsBitwiseCastArg(double a)
     3097{
     3098    Procedure proc;
     3099    BasicBlock* root = proc.addBlock();
     3100    Value* argumentAsInt64 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     3101    Value* argumentAsDouble = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentAsInt64);
     3102    Value* absValue = root->appendNew<Value>(proc, Abs, Origin(), argumentAsDouble);
     3103    Value* resultAsInt64 = root->appendNew<Value>(proc, BitwiseCast, Origin(), absValue);
     3104
     3105    root->appendNew<ControlValue>(proc, Return, Origin(), resultAsInt64);
     3106
     3107    int64_t expectedResult = bitwise_cast<int64_t>(fabs(a));
     3108    CHECK(isIdentical(compileAndRun<int64_t>(proc, bitwise_cast<int64_t>(a)), expectedResult));
     3109}
     3110
     3111void testAbsArg(float a)
     3112{
     3113    Procedure proc;
     3114    BasicBlock* root = proc.addBlock();
     3115    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
     3116        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3117    Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
     3118    Value* result = root->appendNew<Value>(proc, Abs, Origin(), argument);
     3119    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
     3120    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
     3121
     3122    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
     3123}
     3124
     3125void testAbsImm(float a)
     3126{
     3127    Procedure proc;
     3128    BasicBlock* root = proc.addBlock();
     3129    Value* argument = root->appendNew<ConstFloatValue>(proc, Origin(), a);
     3130    Value* result = root->appendNew<Value>(proc, Abs, Origin(), argument);
     3131    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
     3132    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
     3133
     3134    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
     3135}
     3136
     3137void testAbsMem(float a)
     3138{
     3139    Procedure proc;
     3140    BasicBlock* root = proc.addBlock();
     3141    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     3142    MemoryValue* loadFloat = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), address);
     3143    Value* result = root->appendNew<Value>(proc, Abs, Origin(), loadFloat);
     3144    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
     3145    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
     3146
     3147    CHECK(isIdentical(compileAndRun<int32_t>(proc, &a), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
     3148}
     3149
     3150void testAbsAbsArg(float a)
     3151{
     3152    Procedure proc;
     3153    BasicBlock* root = proc.addBlock();
     3154    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
     3155        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3156    Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
     3157    Value* firstAbs = root->appendNew<Value>(proc, Abs, Origin(), argument);
     3158    Value* secondAbs = root->appendNew<Value>(proc, Abs, Origin(), firstAbs);
     3159    root->appendNew<ControlValue>(proc, Return, Origin(), secondAbs);
     3160
     3161    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), static_cast<float>(fabs(a))));
     3162}
     3163
     3164void testAbsBitwiseCastArg(float a)
     3165{
     3166    Procedure proc;
     3167    BasicBlock* root = proc.addBlock();
     3168    Value* argumentAsInt32 = root->appendNew<Value>(proc, Trunc, Origin(),
     3169        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3170    Value* argumentAsfloat = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentAsInt32);
     3171    Value* absValue = root->appendNew<Value>(proc, Abs, Origin(), argumentAsfloat);
     3172    root->appendNew<ControlValue>(proc, Return, Origin(), absValue);
     3173
     3174    CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), static_cast<float>(fabs(a))));
     3175}
     3176
     3177void testBitwiseCastAbsBitwiseCastArg(float a)
     3178{
     3179    Procedure proc;
     3180    BasicBlock* root = proc.addBlock();
     3181    Value* argumentAsInt32 = root->appendNew<Value>(proc, Trunc, Origin(),
     3182        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3183    Value* argumentAsfloat = root->appendNew<Value>(proc, BitwiseCast, Origin(), argumentAsInt32);
     3184    Value* absValue = root->appendNew<Value>(proc, Abs, Origin(), argumentAsfloat);
     3185    Value* resultAsInt64 = root->appendNew<Value>(proc, BitwiseCast, Origin(), absValue);
     3186
     3187    root->appendNew<ControlValue>(proc, Return, Origin(), resultAsInt64);
     3188
     3189    int32_t expectedResult = bitwise_cast<int32_t>(static_cast<float>(fabs(a)));
     3190    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), expectedResult));
     3191}
     3192
     3193void testAbsArgWithUselessDoubleConversion(float a)
     3194{
     3195    Procedure proc;
     3196    BasicBlock* root = proc.addBlock();
     3197    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
     3198        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3199    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
     3200    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
     3201    Value* result = root->appendNew<Value>(proc, Abs, Origin(), asDouble);
     3202    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
     3203    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
     3204    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
     3205
     3206    CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
     3207}
     3208
     3209void testAbsArgWithEffectfulDoubleConversion(float a)
     3210{
     3211    Procedure proc;
     3212    BasicBlock* root = proc.addBlock();
     3213    Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
     3214        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3215    Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
     3216    Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
     3217    Value* result = root->appendNew<Value>(proc, Abs, Origin(), asDouble);
     3218    Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
     3219    Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
     3220    Value* doubleAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     3221    root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleAddress);
     3222    root->appendNew<ControlValue>(proc, Return, Origin(), result32);
     3223
     3224    double effect = 0;
     3225    int32_t resultValue = compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), &effect);
     3226    CHECK(isIdentical(resultValue, bitwise_cast<int32_t>(static_cast<float>(fabs(a)))));
     3227    CHECK(isIdentical(effect, fabs(a)));
    28983228}
    28993229
     
    75167846    RUN(testBitAndImmBitAndArgImm32(24, 0xffff, 7));
    75177847    RUN_BINARY(testBitAndWithMaskReturnsBooleans, int64Operands(), int64Operands());
     7848    RUN_UNARY(testBitAndArgDouble, floatingPointOperands<double>());
     7849    RUN_BINARY(testBitAndArgsDouble, floatingPointOperands<double>(), floatingPointOperands<double>());
     7850    RUN_BINARY(testBitAndArgImmDouble, floatingPointOperands<double>(), floatingPointOperands<double>());
     7851    RUN_BINARY(testBitAndImmsDouble, floatingPointOperands<double>(), floatingPointOperands<double>());
     7852    RUN_UNARY(testBitAndArgFloat, floatingPointOperands<float>());
     7853    RUN_BINARY(testBitAndArgsFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
     7854    RUN_BINARY(testBitAndArgImmFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
     7855    RUN_BINARY(testBitAndImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
     7856    RUN_BINARY(testBitAndArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>());
    75187857
    75197858    RUN(testBitOrArgs(43, 43));
     
    77478086    RUN_UNARY(testClzMem32, int64Operands());
    77488087
     8088    RUN_UNARY(testAbsArg, floatingPointOperands<double>());
     8089    RUN_UNARY(testAbsImm, floatingPointOperands<double>());
     8090    RUN_UNARY(testAbsMem, floatingPointOperands<double>());
     8091    RUN_UNARY(testAbsAbsArg, floatingPointOperands<double>());
     8092    RUN_UNARY(testAbsBitwiseCastArg, floatingPointOperands<double>());
     8093    RUN_UNARY(testBitwiseCastAbsBitwiseCastArg, floatingPointOperands<double>());
     8094    RUN_UNARY(testAbsArg, floatingPointOperands<float>());
     8095    RUN_UNARY(testAbsImm, floatingPointOperands<float>());
     8096    RUN_UNARY(testAbsMem, floatingPointOperands<float>());
     8097    RUN_UNARY(testAbsAbsArg, floatingPointOperands<float>());
     8098    RUN_UNARY(testAbsBitwiseCastArg, floatingPointOperands<float>());
     8099    RUN_UNARY(testBitwiseCastAbsBitwiseCastArg, floatingPointOperands<float>());
     8100    RUN_UNARY(testAbsArgWithUselessDoubleConversion, floatingPointOperands<float>());
     8101    RUN_UNARY(testAbsArgWithEffectfulDoubleConversion, floatingPointOperands<float>());
     8102
    77498103    RUN_UNARY(testSqrtArg, floatingPointOperands<double>());
    77508104    RUN_UNARY(testSqrtImm, floatingPointOperands<double>());
  • trunk/Source/JavaScriptCore/ftl/FTLB3Output.h

    r193989 r194003  
    163163    LValue subWithOverflow64(LValue left, LValue right) { CRASH(); }
    164164    LValue mulWithOverflow64(LValue left, LValue right) { CRASH(); }
    165     LValue doubleAbs(LValue value) { CRASH(); }
     165    LValue doubleAbs(LValue value) { return m_block->appendNew<B3::Value>(m_proc, B3::Abs, origin(), value); }
    166166
    167167    LValue doubleSin(LValue value) { return callWithoutSideEffects(B3::Double, sin, value); }
Note: See TracChangeset for help on using the changeset viewer.