diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 491de07..8a7c9ae 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -156,11 +156,9 @@ typedef enum S390Opcode {
     RXY_LGF     = 0xe314,
     RXY_LGH     = 0xe315,
     RXY_LHY     = 0xe378,
-    RXY_LLC     = 0xe394,
     RXY_LLGC    = 0xe390,
     RXY_LLGF    = 0xe316,
     RXY_LLGH    = 0xe391,
-    RXY_LLH     = 0xe395,
     RXY_LMG     = 0xeb04,
     RXY_LRV     = 0xe31e,
     RXY_LRVG    = 0xe30f,
@@ -653,24 +651,84 @@ static void tcg_out_ld_abs(TCGContext *s, TCGType type, TCGReg dest, void *abs)
     tcg_out_ld(s, type, dest, dest, addr & 0xffff);
 }
 
-static inline void tgen_ext8s(TCGContext *s, TCGReg dest, TCGReg src)
+static void tgen_ext8s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
 {
-    tcg_out_insn(s, RRE, LGBR, dest, src);
+    if (facilities & FACILITY_EXT_IMM) {
+        tcg_out_insn(s, RRE, LGBR, dest, src);
+        return;
+    }
+
+    if (type == TCG_TYPE_I32) {
+        if (dest == src) {
+            tcg_out_sh32(s, RS_SLL, dest, SH32_REG_NONE, 24);
+        } else {
+            tcg_out_sh64(s, RSY_SLLG, dest, src, SH64_REG_NONE, 24);
+        }
+        tcg_out_sh32(s, RS_SRA, dest, SH32_REG_NONE, 24);
+    } else {
+        tcg_out_sh64(s, RSY_SLLG, dest, src, SH64_REG_NONE, 56);
+        tcg_out_sh64(s, RSY_SRAG, dest, dest, SH64_REG_NONE, 56);
+    }
 }
 
-static inline void tgen_ext8u(TCGContext *s, TCGReg dest, TCGReg src)
+static void tgen_ext8u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
 {
-    tcg_out_insn(s, RRE, LLGCR, dest, src);
+    if (facilities & FACILITY_EXT_IMM) {
+        tcg_out_insn(s, RRE, LLGCR, dest, src);
+        return;
+    }
+
+    if (dest == src) {
+        tcg_out_movi(s, type, TCG_TMP0, 0xff);
+        src = TCG_TMP0;
+    } else {
+        tcg_out_movi(s, type, dest, 0xff);
+    }
+    if (type == TCG_TYPE_I32) {
+        tcg_out_insn(s, RR, NR, dest, src);
+    } else {
+        tcg_out_insn(s, RRE, NGR, dest, src);
+    }
 }
 
-static inline void tgen_ext16s(TCGContext *s, TCGReg dest, TCGReg src)
+static void tgen_ext16s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
 {
-    tcg_out_insn(s, RRE, LGHR, dest, src);
+    if (facilities & FACILITY_EXT_IMM) {
+        tcg_out_insn(s, RRE, LGHR, dest, src);
+        return;
+    }
+
+    if (type == TCG_TYPE_I32) {
+        if (dest == src) {
+            tcg_out_sh32(s, RS_SLL, dest, SH32_REG_NONE, 16);
+        } else {
+            tcg_out_sh64(s, RSY_SLLG, dest, src, SH64_REG_NONE, 16);
+        }
+        tcg_out_sh32(s, RS_SRA, dest, SH32_REG_NONE, 24);
+    } else {
+        tcg_out_sh64(s, RSY_SLLG, dest, src, SH64_REG_NONE, 48);
+        tcg_out_sh64(s, RSY_SRAG, dest, dest, SH64_REG_NONE, 48);
+    }
 }
 
-static inline void tgen_ext16u(TCGContext *s, TCGReg dest, TCGReg src)
+static void tgen_ext16u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
 {
-    tcg_out_insn(s, RRE, LLGHR, dest, src);
+    if (facilities & FACILITY_EXT_IMM) {
+        tcg_out_insn(s, RRE, LLGHR, dest, src);
+        return;
+    }
+
+    if (dest == src) {
+        tcg_out_movi(s, type, TCG_TMP0, 0xffff);
+        src = TCG_TMP0;
+    } else {
+        tcg_out_movi(s, type, dest, 0xffff);
+    }
+    if (type == TCG_TYPE_I32) {
+        tcg_out_insn(s, RR, NR, dest, src);
+    } else {
+        tcg_out_insn(s, RRE, NGR, dest, src);
+    }
 }
 
 static inline void tgen_ext32s(TCGContext *s, TCGReg dest, TCGReg src)
@@ -972,7 +1030,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, int opc, TCGReg data,
         if (bswap) {
             /* swapped unsigned halfword load with upper bits zeroed */
             tcg_out_insn(s, RXY, LRVH, data, base, index, disp);
-            tgen_ext16u(s, data, data);
+            tgen_ext16u(s, TCG_TYPE_I64, data, data);
         } else {
             tcg_out_insn(s, RXY, LLGH, data, base, index, disp);
         }
@@ -981,7 +1039,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, int opc, TCGReg data,
         if (bswap) {
             /* swapped sign-extended halfword load */
             tcg_out_insn(s, RXY, LRVH, data, base, index, disp);
-            tgen_ext16s(s, data, data);
+            tgen_ext16s(s, TCG_TYPE_I64, data, data);
         } else {
             tcg_out_insn(s, RXY, LGH, data, base, index, disp);
         }
@@ -1117,10 +1175,10 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg,
         /* sign extension */
         switch (opc) {
         case LD_INT8:
-            tgen_ext8s(s, data_reg, arg0);
+            tgen_ext8s(s, TCG_TYPE_I64, data_reg, arg0);
             break;
         case LD_INT16:
-            tgen_ext16s(s, data_reg, arg0);
+            tgen_ext16s(s, TCG_TYPE_I64, data_reg, arg0);
             break;
         case LD_INT32:
             tgen_ext32s(s, data_reg, arg0);
@@ -1264,23 +1322,22 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         break;
 
     case INDEX_op_ld8u_i32:
-        tcg_out_ldst(s, 0, RXY_LLC, args[0], args[1], args[2]);
-        break;
     case INDEX_op_ld8u_i64:
+        /* ??? LLC (RXY format) is only present with the extended-immediate
+           facility, whereas LLGC is always present.  */
         tcg_out_ldst(s, 0, RXY_LLGC, args[0], args[1], args[2]);
         break;
 
     case INDEX_op_ld8s_i32:
-        tcg_out_ldst(s, 0, RXY_LB, args[0], args[1], args[2]);
-        break;
     case INDEX_op_ld8s_i64:
+        /* ??? LB is no smaller than LGB, so no point to using it.  */
         tcg_out_ldst(s, 0, RXY_LGB, args[0], args[1], args[2]);
         break;
 
     case INDEX_op_ld16u_i32:
-        tcg_out_ldst(s, 0, RXY_LLH, args[0], args[1], args[2]);
-        break;
     case INDEX_op_ld16u_i64:
+        /* ??? LLH (RXY format) is only present with the extended-immediate
+           facility, whereas LLGH is always present.  */
         tcg_out_ldst(s, 0, RXY_LLGH, args[0], args[1], args[2]);
         break;
 
@@ -1517,24 +1574,32 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         break;
 
     case INDEX_op_ext8s_i32:
+        tgen_ext8s(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
     case INDEX_op_ext8s_i64:
-        tgen_ext8s(s, args[0], args[1]);
+        tgen_ext8s(s, TCG_TYPE_I64, args[0], args[1]);
         break;
     case INDEX_op_ext16s_i32:
+        tgen_ext16s(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
     case INDEX_op_ext16s_i64:
-        tgen_ext16s(s, args[0], args[1]);
+        tgen_ext16s(s, TCG_TYPE_I64, args[0], args[1]);
         break;
     case INDEX_op_ext32s_i64:
         tgen_ext32s(s, args[0], args[1]);
         break;
 
     case INDEX_op_ext8u_i32:
+        tgen_ext8u(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
     case INDEX_op_ext8u_i64:
-        tgen_ext8u(s, args[0], args[1]);
+        tgen_ext8u(s, TCG_TYPE_I64, args[0], args[1]);
         break;
     case INDEX_op_ext16u_i32:
+        tgen_ext16u(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
     case INDEX_op_ext16u_i64:
-        tgen_ext16u(s, args[0], args[1]);
+        tgen_ext16u(s, TCG_TYPE_I64, args[0], args[1]);
         break;
     case INDEX_op_ext32u_i64:
         tgen_ext32u(s, args[0], args[1]);
@@ -1545,7 +1610,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         /* The TCG bswap definition requires bits 0-47 already be zero.
            Thus we don't need the G-type insns to implement bswap16_i64.  */
         tcg_out_insn(s, RRE, LRVR, args[0], args[1]);
-        tcg_out_insn(s, RS, SRL, args[0], 0, SH32_REG_NONE, 16);
+        tcg_out_sh32(s, RS_SRL, args[0], SH32_REG_NONE, 16);
         break;
     case INDEX_op_bswap32_i32:
     case INDEX_op_bswap32_i64:
