[JSC] Add B3-to-Air lowering for the shift opcodes
authorbenjamin@webkit.org <benjamin@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Nov 2015 05:50:02 +0000 (05:50 +0000)
committerbenjamin@webkit.org <benjamin@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Nov 2015 05:50:02 +0000 (05:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150919

Patch by Benjamin Poulain <bpoulain@apple.com> on 2015-11-04
Reviewed by Filip Pizlo.

* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::rshift64):
(JSC::MacroAssemblerX86_64::urshift64):
* assembler/X86Assembler.h:
(JSC::X86Assembler::shrq_CLr):
* b3/B3Const32Value.cpp:
(JSC::B3::Const32Value::shlConstant):
(JSC::B3::Const32Value::sShrConstant):
(JSC::B3::Const32Value::zShrConstant):
* b3/B3Const32Value.h:
* b3/B3Const64Value.cpp:
(JSC::B3::Const64Value::shlConstant):
(JSC::B3::Const64Value::sShrConstant):
(JSC::B3::Const64Value::zShrConstant):
* b3/B3Const64Value.h:
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::appendShift):
(JSC::B3::Air::LowerToAir::tryShl):
(JSC::B3::Air::LowerToAir::trySShr):
(JSC::B3::Air::LowerToAir::tryZShr):
* b3/B3LoweringMatcher.patterns:
* b3/B3Opcode.h:
* b3/B3ReduceStrength.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::shlConstant):
(JSC::B3::Value::sShrConstant):
(JSC::B3::Value::zShrConstant):
* b3/B3Value.h:
* b3/air/AirInstInlines.h:
(JSC::B3::Air::isShiftValid):
(JSC::B3::Air::isRshift32Valid):
(JSC::B3::Air::isRshift64Valid):
(JSC::B3::Air::isUrshift32Valid):
(JSC::B3::Air::isUrshift64Valid):
* b3/air/AirOpcode.opcodes:
* b3/testb3.cpp:
(JSC::B3::testShlArgs):
(JSC::B3::testShlImms):
(JSC::B3::testShlArgImm):
(JSC::B3::testShlArgs32):
(JSC::B3::testShlImms32):
(JSC::B3::testShlArgImm32):
(JSC::B3::testSShrArgs):
(JSC::B3::testSShrImms):
(JSC::B3::testSShrArgImm):
(JSC::B3::testSShrArgs32):
(JSC::B3::testSShrImms32):
(JSC::B3::testSShrArgImm32):
(JSC::B3::testZShrArgs):
(JSC::B3::testZShrImms):
(JSC::B3::testZShrArgImm):
(JSC::B3::testZShrArgs32):
(JSC::B3::testZShrImms32):
(JSC::B3::testZShrArgImm32):
(JSC::B3::run):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192051 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
Source/JavaScriptCore/assembler/X86Assembler.h
Source/JavaScriptCore/b3/B3Const32Value.cpp
Source/JavaScriptCore/b3/B3Const32Value.h
Source/JavaScriptCore/b3/B3Const64Value.cpp
Source/JavaScriptCore/b3/B3Const64Value.h
Source/JavaScriptCore/b3/B3LowerToAir.cpp
Source/JavaScriptCore/b3/B3LoweringMatcher.patterns
Source/JavaScriptCore/b3/B3Opcode.h
Source/JavaScriptCore/b3/B3ReduceStrength.cpp
Source/JavaScriptCore/b3/B3Value.cpp
Source/JavaScriptCore/b3/B3Value.h
Source/JavaScriptCore/b3/air/AirInstInlines.h
Source/JavaScriptCore/b3/air/AirOpcode.opcodes
Source/JavaScriptCore/b3/testb3.cpp

index 3e91111..9786bf4 100644 (file)
@@ -1,3 +1,66 @@
+2015-11-04  Benjamin Poulain  <bpoulain@apple.com>
+
+        [JSC] Add B3-to-Air lowering for the shift opcodes
+        https://bugs.webkit.org/show_bug.cgi?id=150919
+
+        Reviewed by Filip Pizlo.
+
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::rshift64):
+        (JSC::MacroAssemblerX86_64::urshift64):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::shrq_CLr):
+        * b3/B3Const32Value.cpp:
+        (JSC::B3::Const32Value::shlConstant):
+        (JSC::B3::Const32Value::sShrConstant):
+        (JSC::B3::Const32Value::zShrConstant):
+        * b3/B3Const32Value.h:
+        * b3/B3Const64Value.cpp:
+        (JSC::B3::Const64Value::shlConstant):
+        (JSC::B3::Const64Value::sShrConstant):
+        (JSC::B3::Const64Value::zShrConstant):
+        * b3/B3Const64Value.h:
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::appendShift):
+        (JSC::B3::Air::LowerToAir::tryShl):
+        (JSC::B3::Air::LowerToAir::trySShr):
+        (JSC::B3::Air::LowerToAir::tryZShr):
+        * b3/B3LoweringMatcher.patterns:
+        * b3/B3Opcode.h:
+        * b3/B3ReduceStrength.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::shlConstant):
+        (JSC::B3::Value::sShrConstant):
+        (JSC::B3::Value::zShrConstant):
+        * b3/B3Value.h:
+        * b3/air/AirInstInlines.h:
+        (JSC::B3::Air::isShiftValid):
+        (JSC::B3::Air::isRshift32Valid):
+        (JSC::B3::Air::isRshift64Valid):
+        (JSC::B3::Air::isUrshift32Valid):
+        (JSC::B3::Air::isUrshift64Valid):
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.cpp:
+        (JSC::B3::testShlArgs):
+        (JSC::B3::testShlImms):
+        (JSC::B3::testShlArgImm):
+        (JSC::B3::testShlArgs32):
+        (JSC::B3::testShlImms32):
+        (JSC::B3::testShlArgImm32):
+        (JSC::B3::testSShrArgs):
+        (JSC::B3::testSShrImms):
+        (JSC::B3::testSShrArgImm):
+        (JSC::B3::testSShrArgs32):
+        (JSC::B3::testSShrImms32):
+        (JSC::B3::testSShrArgImm32):
+        (JSC::B3::testZShrArgs):
+        (JSC::B3::testZShrImms):
+        (JSC::B3::testZShrArgImm):
+        (JSC::B3::testZShrArgs32):
+        (JSC::B3::testZShrImms32):
+        (JSC::B3::testZShrArgImm32):
+        (JSC::B3::run):
+
 2015-11-03  Filip Pizlo  <fpizlo@apple.com>
 
         B3 should be able to compile a Check
index 3b70d38..d1c8dd0 100644 (file)
@@ -347,12 +347,40 @@ public:
     {
         m_assembler.sarq_i8r(imm.m_value, dest);
     }
-    
+
+    void rshift64(RegisterID src, RegisterID dest)
+    {
+        ASSERT(src != dest);
+
+        if (src == X86Registers::ecx)
+            m_assembler.sarq_CLr(dest);
+        else {
+            // Can only shift by ecx, so we do some swapping if we see anything else.
+            swap(src, X86Registers::ecx);
+            m_assembler.sarq_CLr(dest);
+            swap(src, X86Registers::ecx);
+        }
+    }
+
     void urshift64(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.shrq_i8r(imm.m_value, dest);
     }
-    
+
+    void urshift64(RegisterID src, RegisterID dest)
+    {
+        ASSERT(src != dest);
+
+        if (src == X86Registers::ecx)
+            m_assembler.shrq_CLr(dest);
+        else {
+            // Can only shift by ecx, so we do some swapping if we see anything else.
+            swap(src, X86Registers::ecx);
+            m_assembler.shrq_CLr(dest);
+            swap(src, X86Registers::ecx);
+        }
+    }
+
     void mul64(RegisterID src, RegisterID dest)
     {
         m_assembler.imulq_rr(src, dest);
index 482e6fa..abbf2e3 100644 (file)
@@ -901,6 +901,11 @@ public:
         }
     }
 
+    void shrq_CLr(RegisterID dst)
+    {
+        m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SHR, dst);
+    }
+
     void shlq_i8r(int imm, RegisterID dst)
     {
         if (imm == 1)
index f86e397..25dea85 100644 (file)
@@ -82,6 +82,27 @@ Value* Const32Value::bitXorConstant(Procedure& proc, Value* other) const
     return proc.add<Const32Value>(origin(), m_value ^ other->asInt32());
 }
 
+Value* Const32Value::shlConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasInt32())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), m_value << (other->asInt32() & 31));
+}
+
+Value* Const32Value::sShrConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasInt32())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), m_value >> (other->asInt32() & 31));
+}
+
+Value* Const32Value::zShrConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasInt32())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), static_cast<int32_t>(static_cast<uint32_t>(m_value) >> (other->asInt32() & 31)));
+}
+
 Value* Const32Value::equalConstant(Procedure& proc, Value* other) const
 {
     if (!other->hasInt32())
index 7680f70..64afa48 100644 (file)
@@ -47,6 +47,9 @@ public:
     Value* bitAndConstant(Procedure&, Value* other) const override;
     Value* bitOrConstant(Procedure&, Value* other) const override;
     Value* bitXorConstant(Procedure&, Value* other) const override;
+    Value* shlConstant(Procedure&, Value* other) const override;
+    Value* sShrConstant(Procedure&, Value* other) const override;
+    Value* zShrConstant(Procedure&, Value* other) const override;
     Value* equalConstant(Procedure&, Value* other) const override;
     Value* notEqualConstant(Procedure&, Value* other) const override;
 
index 2377a94..1a4eba3 100644 (file)
@@ -82,6 +82,27 @@ Value* Const64Value::bitXorConstant(Procedure& proc, Value* other) const
     return proc.add<Const64Value>(origin(), m_value ^ other->asInt64());
 }
 
+Value* Const64Value::shlConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasInt32())
+        return nullptr;
+    return proc.add<Const64Value>(origin(), m_value << (other->asInt32() & 63));
+}
+
+Value* Const64Value::sShrConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasInt32())
+        return nullptr;
+    return proc.add<Const64Value>(origin(), m_value >> (other->asInt32() & 63));
+}
+
+Value* Const64Value::zShrConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasInt32())
+        return nullptr;
+    return proc.add<Const64Value>(origin(), static_cast<int64_t>(static_cast<uint64_t>(m_value) >> (other->asInt32() & 63)));
+}
+
 Value* Const64Value::equalConstant(Procedure& proc, Value* other) const
 {
     if (!other->hasInt64())
index 29e9e2a..bfdd9d2 100644 (file)
@@ -47,6 +47,9 @@ public:
     Value* bitAndConstant(Procedure&, Value* other) const override;
     Value* bitOrConstant(Procedure&, Value* other) const override;
     Value* bitXorConstant(Procedure&, Value* other) const override;
+    Value* shlConstant(Procedure&, Value* other) const override;
+    Value* sShrConstant(Procedure&, Value* other) const override;
+    Value* zShrConstant(Procedure&, Value* other) const override;
     Value* equalConstant(Procedure&, Value* other) const override;
     Value* notEqualConstant(Procedure&, Value* other) const override;
 
index 4972eee..2f8548a 100644 (file)
@@ -754,19 +754,37 @@ public:
         }
     }
 
-    bool tryShl(Value* value, Value* amount)
+    void appendShift(Air::Opcode opcode, Value* value, Value* amount)
     {
-        Air::Opcode opcode = value->type() == Int32 ? Lshift32 : Lshift64;
-
         if (imm(amount)) {
             append(Move, tmp(value), tmp(currentValue));
             append(opcode, imm(amount), tmp(currentValue));
-            return true;
+            return;
         }
 
         append(Move, tmp(value), tmp(currentValue));
         append(Move, tmp(amount), Tmp(X86Registers::ecx));
         append(opcode, Tmp(X86Registers::ecx), tmp(currentValue));
+    }
+
+    bool tryShl(Value* value, Value* amount)
+    {
+        Air::Opcode opcode = value->type() == Int32 ? Lshift32 : Lshift64;
+        appendShift(opcode, value, amount);
+        return true;
+    }
+
+    bool trySShr(Value* value, Value* amount)
+    {
+        Air::Opcode opcode = value->type() == Int32 ? Rshift32 : Rshift64;
+        appendShift(opcode, value, amount);
+        return true;
+    }
+
+    bool tryZShr(Value* value, Value* amount)
+    {
+        Air::Opcode opcode = value->type() == Int32 ? Urshift32 : Urshift64;
+        appendShift(opcode, value, amount);
         return true;
     }
     
index 588fc96..1c9c829 100644 (file)
@@ -37,6 +37,8 @@ Or = BitOr(left, right)
 Xor = BitXor(left, right)
 
 Shl = Shl(value, amount)
+SShr = SShr(value, amount)
+ZShr = ZShr(value, amount)
 
 StoreAddLoad = Store(Add(left, right), address)
 StoreSubLoad = Store(Sub(left, right), address)
index 0ce09c6..540bbe8 100644 (file)
@@ -76,8 +76,8 @@ enum Opcode : int16_t {
     BitOr,
     BitXor,
     Shl,
-    SShr,
-    ZShr,
+    SShr, // Arithmetic Shift.
+    ZShr, // Logical Shift.
 
     // Casts and such.
     // Takes and returns Int32:
index 3562013..4180115 100644 (file)
@@ -283,6 +283,45 @@ private:
 
             break;
 
+        case Shl:
+            // Turn this: Shl(constant1, constant2)
+            // Into this: constant1 << constant2
+            if (Value* constant = m_value->child(0)->shlConstant(m_proc, m_value->child(1))) {
+                replaceWithNewValue(constant);
+                break;
+            }
+
+            if (handleShiftByZero())
+                break;
+
+            break;
+
+        case SShr:
+            // Turn this: SShr(constant1, constant2)
+            // Into this: constant1 >> constant2
+            if (Value* constant = m_value->child(0)->sShrConstant(m_proc, m_value->child(1))) {
+                replaceWithNewValue(constant);
+                break;
+            }
+
+            if (handleShiftByZero())
+                break;
+
+            break;
+
+        case ZShr:
+            // Turn this: ZShr(constant1, constant2)
+            // Into this: (unsigned)constant1 >> constant2
+            if (Value* constant = m_value->child(0)->zShrConstant(m_proc, m_value->child(1))) {
+                replaceWithNewValue(constant);
+                break;
+            }
+
+            if (handleShiftByZero())
+                break;
+
+            break;
+
         case Load8Z:
         case Load8S:
         case Load16Z:
@@ -478,6 +517,17 @@ private:
         m_changed = true;
     }
 
+    bool handleShiftByZero()
+    {
+        // Shift anything by zero is identity.
+        if (m_value->child(1)->isInt(0)) {
+            m_value->replaceWithIdentity(m_value->child(0));
+            m_changed = true;
+            return true;
+        }
+        return false;
+    }
+
     void killDeadCode()
     {
         GraphNodeWorklist<Value*, IndexSet<Value>> worklist;
index c3b1bb0..5179597 100644 (file)
@@ -147,6 +147,21 @@ Value* Value::bitXorConstant(Procedure&, Value*) const
     return nullptr;
 }
 
+Value* Value::shlConstant(Procedure&, Value*) const
+{
+    return nullptr;
+}
+
+Value* Value::sShrConstant(Procedure&, Value*) const
+{
+    return nullptr;
+}
+
+Value* Value::zShrConstant(Procedure&, Value*) const
+{
+    return nullptr;
+}
+
 Value* Value::equalConstant(Procedure&, Value*) const
 {
     return nullptr;
index 38e5d94..f79f0e4 100644 (file)
@@ -115,6 +115,9 @@ public:
     virtual Value* bitAndConstant(Procedure&, Value* other) const;
     virtual Value* bitOrConstant(Procedure&, Value* other) const;
     virtual Value* bitXorConstant(Procedure&, Value* other) const;
+    virtual Value* shlConstant(Procedure&, Value* other) const;
+    virtual Value* sShrConstant(Procedure&, Value* other) const;
+    virtual Value* zShrConstant(Procedure&, Value* other) const;
     virtual Value* equalConstant(Procedure&, Value* other) const;
     virtual Value* notEqualConstant(Procedure&, Value* other) const;
 
index 80670c6..917f64c 100644 (file)
@@ -96,7 +96,7 @@ inline bool isShiftValid(const Inst& inst)
     UNUSED_PARAM(inst);
     return true;
 #endif
-}   
+}
 
 inline bool isLshift32Valid(const Inst& inst)
 {
@@ -108,6 +108,26 @@ inline bool isLshift64Valid(const Inst& inst)
     return isShiftValid(inst);
 }
 
+inline bool isRshift32Valid(const Inst& inst)
+{
+    return isShiftValid(inst);
+}
+
+inline bool isRshift64Valid(const Inst& inst)
+{
+    return isShiftValid(inst);
+}
+
+inline bool isUrshift32Valid(const Inst& inst)
+{
+    return isShiftValid(inst);
+}
+
+inline bool isUrshift64Valid(const Inst& inst)
+{
+    return isShiftValid(inst);
+}
+
 } } } // namespace JSC::B3::Air
 
 #endif // ENABLE(B3_JIT)
index f24ac6b..735f55a 100644 (file)
@@ -114,6 +114,26 @@ Lshift32 U:G, UD:G
     Tmp*, Tmp
     Imm, Tmp
 
+Lshift64 U:G, UD:G
+    Tmp*, Tmp
+    Imm, Tmp
+
+Rshift32 U:G, UD:G
+    Tmp*, Tmp
+    Imm, Tmp
+
+Rshift64 U:G, UD:G
+    Tmp*, Tmp
+    Imm, Tmp
+
+Urshift32 U:G, UD:G
+    Tmp*, Tmp
+    Imm, Tmp
+
+Urshift64 U:G, UD:G
+    Tmp*, Tmp
+    Imm, Tmp
+
 Or32 U:G, UD:G
     Tmp, Tmp
     Imm, Tmp
@@ -137,10 +157,6 @@ Xor64 U:G, UD:G
     Tmp, Addr
     Imm, Tmp
 
-Lshift64 U:G, UD:G
-    Tmp*, Tmp
-    Imm, Tmp
-
 Mul32 U:G, UD:G
     Tmp, Tmp
     Addr, Tmp
index 48d7596..ba6a4d8 100644 (file)
@@ -966,6 +966,282 @@ void testBitXorImmBitXorArgImm32(int a, int b, int c)
     CHECK(compileAndRun<int>(proc, b) == (a ^ (b ^ c)));
 }
 
+void testShlArgs(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+
+    CHECK(compileAndRun<int64_t>(proc, a, b) == (a << b));
+}
+
+void testShlImms(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<int64_t>(proc) == (a << b));
+}
+
+void testShlArgImm(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<int64_t>(proc, a) == (a << b));
+}
+
+void testShlArgs32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+
+    CHECK(compileAndRun<int32_t>(proc, a, b) == (a << b));
+}
+
+void testShlImms32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<int32_t>(proc) == (a << b));
+}
+
+void testShlArgImm32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, Shl, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<int32_t>(proc, a) == (a << b));
+}
+
+void testSShrArgs(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SShr, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+
+    CHECK(compileAndRun<int64_t>(proc, a, b) == (a >> b));
+}
+
+void testSShrImms(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SShr, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<int64_t>(proc) == (a >> b));
+}
+
+void testSShrArgImm(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SShr, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<int64_t>(proc, a) == (a >> b));
+}
+
+void testSShrArgs32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SShr, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+
+    CHECK(compileAndRun<int32_t>(proc, a, b) == (a >> b));
+}
+
+void testSShrImms32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SShr, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<int32_t>(proc) == (a >> b));
+}
+
+void testSShrArgImm32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, SShr, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<int32_t>(proc, a) == (a >> b));
+}
+
+void testZShrArgs(uint64_t a, uint64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, ZShr, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+
+    CHECK(compileAndRun<uint64_t>(proc, a, b) == (a >> b));
+}
+
+void testZShrImms(uint64_t a, uint64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, ZShr, Origin(),
+            root->appendNew<Const64Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<uint64_t>(proc) == (a >> b));
+}
+
+void testZShrArgImm(uint64_t a, uint64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, ZShr, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<uint64_t>(proc, a) == (a >> b));
+}
+
+void testZShrArgs32(uint32_t a, uint32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, ZShr, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))));
+
+    CHECK(compileAndRun<uint32_t>(proc, a, b) == (a >> b));
+}
+
+void testZShrImms32(uint32_t a, uint32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, ZShr, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), a),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<uint32_t>(proc) == (a >> b));
+}
+
+void testZShrArgImm32(uint32_t a, uint32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, ZShr, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), b)));
+
+    CHECK(compileAndRun<uint32_t>(proc, a) == (a >> b));
+}
+
 void testStore(int value)
 {
     Procedure proc;
@@ -2245,6 +2521,129 @@ void run(const char* filter)
     RUN(testBitXorImmBitXorArgImm32(6, 1, 6));
     RUN(testBitXorImmBitXorArgImm32(24, 0xffff, 7));
 
+    RUN(testShlArgs(1, 0));
+    RUN(testShlArgs(1, 1));
+    RUN(testShlArgs(1, 62));
+    RUN(testShlArgs(0xffffffffffffffff, 0));
+    RUN(testShlArgs(0xffffffffffffffff, 1));
+    RUN(testShlArgs(0xffffffffffffffff, 63));
+    RUN(testShlImms(1, 0));
+    RUN(testShlImms(1, 1));
+    RUN(testShlImms(1, 62));
+    RUN(testShlImms(1, 65));
+    RUN(testShlImms(0xffffffffffffffff, 0));
+    RUN(testShlImms(0xffffffffffffffff, 1));
+    RUN(testShlImms(0xffffffffffffffff, 63));
+    RUN(testShlArgImm(1, 0));
+    RUN(testShlArgImm(1, 1));
+    RUN(testShlArgImm(1, 62));
+    RUN(testShlArgImm(1, 65));
+    RUN(testShlArgImm(0xffffffffffffffff, 0));
+    RUN(testShlArgImm(0xffffffffffffffff, 1));
+    RUN(testShlArgImm(0xffffffffffffffff, 63));
+    RUN(testShlArgs32(1, 0));
+    RUN(testShlArgs32(1, 1));
+    RUN(testShlArgs32(1, 62));
+    RUN(testShlImms32(1, 33));
+    RUN(testShlArgs32(0xffffffff, 0));
+    RUN(testShlArgs32(0xffffffff, 1));
+    RUN(testShlArgs32(0xffffffff, 63));
+    RUN(testShlImms32(1, 0));
+    RUN(testShlImms32(1, 1));
+    RUN(testShlImms32(1, 62));
+    RUN(testShlImms32(1, 33));
+    RUN(testShlImms32(0xffffffff, 0));
+    RUN(testShlImms32(0xffffffff, 1));
+    RUN(testShlImms32(0xffffffff, 63));
+    RUN(testShlArgImm32(1, 0));
+    RUN(testShlArgImm32(1, 1));
+    RUN(testShlArgImm32(1, 62));
+    RUN(testShlArgImm32(0xffffffff, 0));
+    RUN(testShlArgImm32(0xffffffff, 1));
+    RUN(testShlArgImm32(0xffffffff, 63));
+
+    RUN(testSShrArgs(1, 0));
+    RUN(testSShrArgs(1, 1));
+    RUN(testSShrArgs(1, 62));
+    RUN(testSShrArgs(0xffffffffffffffff, 0));
+    RUN(testSShrArgs(0xffffffffffffffff, 1));
+    RUN(testSShrArgs(0xffffffffffffffff, 63));
+    RUN(testSShrImms(1, 0));
+    RUN(testSShrImms(1, 1));
+    RUN(testSShrImms(1, 62));
+    RUN(testSShrImms(1, 65));
+    RUN(testSShrImms(0xffffffffffffffff, 0));
+    RUN(testSShrImms(0xffffffffffffffff, 1));
+    RUN(testSShrImms(0xffffffffffffffff, 63));
+    RUN(testSShrArgImm(1, 0));
+    RUN(testSShrArgImm(1, 1));
+    RUN(testSShrArgImm(1, 62));
+    RUN(testSShrArgImm(1, 65));
+    RUN(testSShrArgImm(0xffffffffffffffff, 0));
+    RUN(testSShrArgImm(0xffffffffffffffff, 1));
+    RUN(testSShrArgImm(0xffffffffffffffff, 63));
+    RUN(testSShrArgs32(1, 0));
+    RUN(testSShrArgs32(1, 1));
+    RUN(testSShrArgs32(1, 62));
+    RUN(testSShrArgs32(1, 33));
+    RUN(testSShrArgs32(0xffffffff, 0));
+    RUN(testSShrArgs32(0xffffffff, 1));
+    RUN(testSShrArgs32(0xffffffff, 63));
+    RUN(testSShrImms32(1, 0));
+    RUN(testSShrImms32(1, 1));
+    RUN(testSShrImms32(1, 62));
+    RUN(testSShrImms32(1, 33));
+    RUN(testSShrImms32(0xffffffff, 0));
+    RUN(testSShrImms32(0xffffffff, 1));
+    RUN(testSShrImms32(0xffffffff, 63));
+    RUN(testSShrArgImm32(1, 0));
+    RUN(testSShrArgImm32(1, 1));
+    RUN(testSShrArgImm32(1, 62));
+    RUN(testSShrArgImm32(0xffffffff, 0));
+    RUN(testSShrArgImm32(0xffffffff, 1));
+    RUN(testSShrArgImm32(0xffffffff, 63));
+
+    RUN(testZShrArgs(1, 0));
+    RUN(testZShrArgs(1, 1));
+    RUN(testZShrArgs(1, 62));
+    RUN(testZShrArgs(0xffffffffffffffff, 0));
+    RUN(testZShrArgs(0xffffffffffffffff, 1));
+    RUN(testZShrArgs(0xffffffffffffffff, 63));
+    RUN(testZShrImms(1, 0));
+    RUN(testZShrImms(1, 1));
+    RUN(testZShrImms(1, 62));
+    RUN(testZShrImms(1, 65));
+    RUN(testZShrImms(0xffffffffffffffff, 0));
+    RUN(testZShrImms(0xffffffffffffffff, 1));
+    RUN(testZShrImms(0xffffffffffffffff, 63));
+    RUN(testZShrArgImm(1, 0));
+    RUN(testZShrArgImm(1, 1));
+    RUN(testZShrArgImm(1, 62));
+    RUN(testZShrArgImm(1, 65));
+    RUN(testZShrArgImm(0xffffffffffffffff, 0));
+    RUN(testZShrArgImm(0xffffffffffffffff, 1));
+    RUN(testZShrArgImm(0xffffffffffffffff, 63));
+    RUN(testZShrArgs32(1, 0));
+    RUN(testZShrArgs32(1, 1));
+    RUN(testZShrArgs32(1, 62));
+    RUN(testZShrArgs32(1, 33));
+    RUN(testZShrArgs32(0xffffffff, 0));
+    RUN(testZShrArgs32(0xffffffff, 1));
+    RUN(testZShrArgs32(0xffffffff, 63));
+    RUN(testZShrImms32(1, 0));
+    RUN(testZShrImms32(1, 1));
+    RUN(testZShrImms32(1, 62));
+    RUN(testZShrImms32(1, 33));
+    RUN(testZShrImms32(0xffffffff, 0));
+    RUN(testZShrImms32(0xffffffff, 1));
+    RUN(testZShrImms32(0xffffffff, 63));
+    RUN(testZShrArgImm32(1, 0));
+    RUN(testZShrArgImm32(1, 1));
+    RUN(testZShrArgImm32(1, 62));
+    RUN(testZShrArgImm32(0xffffffff, 0));
+    RUN(testZShrArgImm32(0xffffffff, 1));
+    RUN(testZShrArgImm32(0xffffffff, 63));
+
     RUN(testStore(44));
     RUN(testStoreConstant(49));
     RUN(testStoreConstantPtr(49));