diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index aecabf9..b66778a 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -33,9 +33,10 @@
     do { } while (0)
 #endif
 
-#define TCG_CT_CONST_S32   0x100
-#define TCG_CT_CONST_N32   0x200
-#define TCG_CT_CONST_MULI  0x400
+#define TCG_CT_CONST_32    0x100
+#define TCG_CT_CONST_NEG   0x200
+#define TCG_CT_CONST_ADDI  0x400
+#define TCG_CT_CONST_MULI  0x800
 
 #define TCG_TMP0           TCG_REG_R14
 
@@ -57,6 +58,7 @@
 typedef enum S390Opcode {
     RIL_AFI     = 0xc209,
     RIL_AGFI    = 0xc208,
+    RIL_ALGFI   = 0xc20a,
     RIL_BRASL   = 0xc005,
     RIL_BRCL    = 0xc004,
     RIL_IIHF    = 0xc008,
@@ -337,13 +339,17 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
         tcg_regset_clear(ct->u.regs);
         tcg_regset_set_reg(ct->u.regs, TCG_REG_R3);
         break;
-    case 'I':
+    case 'N':                  /* force immediate negate */
+        ct->ct &= ~TCG_CT_REG;
+        ct->ct |= TCG_CT_CONST_NEG;
+        break;
+    case 'W':                  /* force 32-bit ("word") immediate */
         ct->ct &= ~TCG_CT_REG;
-        ct->ct |= TCG_CT_CONST_S32;
+        ct->ct |= TCG_CT_CONST_32;
         break;
-    case 'J':
+    case 'I':
         ct->ct &= ~TCG_CT_REG;
-        ct->ct |= TCG_CT_CONST_N32;
+        ct->ct |= TCG_CT_CONST_ADDI;
         break;
     case 'K':
         ct->ct &= ~TCG_CT_REG;
@@ -366,10 +372,27 @@ static inline int tcg_target_const_match(tcg_target_long val,
 
     if (ct & TCG_CT_CONST) {
         return 1;
-    } else if (ct & TCG_CT_CONST_S32) {
-        return val == (int32_t)val;
-    } else if (ct & TCG_CT_CONST_N32) {
-        return -val == (int32_t)-val;
+    }
+
+    /* Handle the modifiers.  */
+    if (ct & TCG_CT_CONST_NEG) {
+        val = -val;
+    }
+    if (ct & TCG_CT_CONST_32) {
+        val = (int32_t)val;
+    }
+
+    /* The following are mutually exclusive.  */
+    if (ct & TCG_CT_CONST_ADDI) {
+        /* Immediates that may be used with add.  If we have the
+           extended-immediates facility then we have ADD IMMEDIATE
+           with signed and unsigned 32-bit, otherwise we have only
+           ADD HALFWORD IMMEDIATE with a signed 16-bit.  */
+        if (facilities & FACILITY_EXT_IMM) {
+            return val == (int32_t)val || val == (uint32_t)val;
+        } else {
+            return val == (int16_t)val;
+        }
     } else if (ct & TCG_CT_CONST_MULI) {
         /* Immediates that may be used with multiply.  If we have the
            general-instruction-extensions, then we have MULTIPLY SINGLE
@@ -621,7 +644,7 @@ static inline void tgen_ext32u(TCGContext *s, TCGReg dest, TCGReg src)
     tcg_out_insn(s, RRE, LLGFR, dest, src);
 }
 
-static inline void tgen32_addi(TCGContext *s, TCGReg dest, tcg_target_long val)
+static void tgen32_addi(TCGContext *s, TCGReg dest, int32_t val)
 {
     if (val == (int16_t)val) {
         tcg_out_insn(s, RI, AHI, dest, val);
@@ -630,13 +653,18 @@ static inline void tgen32_addi(TCGContext *s, TCGReg dest, tcg_target_long val)
     }
 }
 
-static inline void tgen64_addi(TCGContext *s, TCGReg dest, tcg_target_long val)
+static void tgen64_addi(TCGContext *s, TCGReg dest, int64_t val)
 {
     if (val == (int16_t)val) {
         tcg_out_insn(s, RI, AGHI, dest, val);
-    } else {
+    } else if (val == (int32_t)val) {
         tcg_out_insn(s, RIL, AGFI, dest, val);
+    } else if (val == (uint32_t)val) {
+        tcg_out_insn(s, RIL, ALGFI, dest, val);
+    } else {
+        tcg_abort();
     }
+
 }
 
 static void tgen32_andi(TCGContext *s, TCGReg dest, uint32_t val)
@@ -1589,9 +1617,9 @@ static const TCGTargetOpDef s390_op_defs[] = {
     { INDEX_op_st16_i32, { "r", "r" } },
     { INDEX_op_st_i32, { "r", "r" } },
 
-    { INDEX_op_add_i32, { "r", "0", "ri" } },
-    { INDEX_op_sub_i32, { "r", "0", "ri" } },
-    { INDEX_op_mul_i32, { "r", "0", "rK" } },
+    { INDEX_op_add_i32, { "r", "0", "rWI" } },
+    { INDEX_op_sub_i32, { "r", "0", "rWNI" } },
+    { INDEX_op_mul_i32, { "r", "0", "rWK" } },
 
     { INDEX_op_div2_i32, { "b", "a", "0", "1", "r" } },
     { INDEX_op_divu2_i32, { "b", "a", "0", "1", "r" } },
@@ -1651,7 +1679,7 @@ static const TCGTargetOpDef s390_op_defs[] = {
     { INDEX_op_st_i64, { "r", "r" } },
 
     { INDEX_op_add_i64, { "r", "0", "rI" } },
-    { INDEX_op_sub_i64, { "r", "0", "rJ" } },
+    { INDEX_op_sub_i64, { "r", "0", "rNI" } },
     { INDEX_op_mul_i64, { "r", "0", "rK" } },
 
     { INDEX_op_div2_i64, { "b", "a", "0", "1", "r" } },
