Index: gcc/config/avr/avr.md
===================================================================
--- gcc/config/avr/avr.md	(revision 143546)
+++ gcc/config/avr/avr.md	(working copy)
@@ -59,7 +59,10 @@
    (UNSPECV_EPILOGUE_RESTORES	1)
    (UNSPECV_WRITE_SP_IRQ_ON	2)
    (UNSPECV_WRITE_SP_IRQ_OFF	3)
-   (UNSPECV_GOTO_RECEIVER	4)])
+   (UNSPECV_GOTO_RECEIVER	4)
+
+   (UNSPEC_LPM 10)
+   ])
 
 (include "predicates.md")
 (include "constraints.md")
@@ -3262,3 +3265,102 @@
     expand_epilogue (); 
     DONE;
   }")
+
+
+(define_expand "pgm_read_byte"
+  [(parallel[(match_operand:QI 0 "register_operand" "")
+             (match_operand:HI 1 "register_operand" "")])]
+  ""
+  {
+     rtx Z = gen_rtx_REG (HImode, REG_Z);
+        rtx reg_z  = gen_reg_rtx (HImode);
+        rtx reg_z1 = gen_reg_rtx (HImode);
+
+        switch (avr_test)
+        {
+            case 0:
+                emit_move_insn (Z, operands[1]);
+                emit_insn (gen_lpmZ_postinc (operands[0]));
+                break;
+
+            case 1:
+                emit_move_insn (Z, operands[1]);
+                emit_insn (gen_lpmZ_postinc_1 (operands[0]));
+                break;
+
+            case 2:
+                /* Allow modified Z to have other pseudo number than Z */
+                emit_move_insn (Z, operands[1]);
+                emit_insn (gen_lpmZ_postinc_2 (operands[0], reg_z1));
+                break;
+
+            case 3:
+                /* Allow modified Z to have other pseudo number than Z */
+                emit_move_insn (reg_z,  operands[1]);
+                emit_insn (gen_lpmZ_postinc_3 (operands[0], reg_z1, reg_z));
+                break;
+
+            default: abort();
+        }
+
+        DONE;
+  }) 
+
+;; %0 = *Z
+(define_insn "lpmZ"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+        (unspec:QI [(mem:QI (reg:HI REG_Z))
+                    ] UNSPEC_LPM))]
+  ""
+  "lpm %0, Z" 
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+
+;; %0 = *Z++
+(define_insn "lpmZ_postinc"
+  [(set (reg:HI REG_Z)
+        (plus:HI (reg:HI REG_Z)
+                 (const_int 1)))
+  (set (match_operand:QI 0 "register_operand" "=r")
+       (unspec:QI [(mem:QI (reg:HI REG_Z))
+                   ] UNSPEC_LPM))]
+  ""
+  "lpm %0, Z+" 
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+
+
+(define_insn "lpmZ_postinc_1"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+        (unspec:QI [(mem:QI (post_inc (reg:HI REG_Z)))
+                   ] UNSPEC_LPM))]
+  ""
+  "lpm %0, Z+" 
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+ 
+(define_insn "lpmZ_postinc_2"
+  [(set (match_operand:HI 1 "register_operand" "+z")
+        (plus:HI (reg:HI REG_Z)
+                 (const_int 1)))
+
+   (set (match_operand:QI 0 "register_operand" "=r")
+        (unspec:QI [(mem:QI (reg:HI REG_Z))
+                    ] UNSPEC_LPM))]
+  ""
+  "lpm %0, Z+" 
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+
+(define_insn "lpmZ_postinc_3"
+  [(set (match_operand:HI 1 "register_operand" "=z")
+        (plus:HI (match_operand:HI 2 "register_operand" "z")
+                 (const_int 1)))
+
+   (set (match_operand:QI 0 "register_operand" "=r")
+        (unspec:QI [(mem:QI (match_dup 2))
+                    ] UNSPEC_LPM))]
+  ""
+  "lpm %0, Z+" 
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
Index: gcc/config/avr/avr.c
===================================================================
--- gcc/config/avr/avr.c	(revision 143546)
+++ gcc/config/avr/avr.c	(working copy)
@@ -29,6 +29,7 @@
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
+#include "insn-codes.h"
 #include "insn-attr.h"
 #include "flags.h"
 #include "reload.h"
@@ -45,6 +46,8 @@
 #include "target-def.h"
 #include "params.h"
 #include "df.h"
+#include "langhooks.h"
+#include "optabs.h"		/* For GEN_FCN */
 
 /* Maximal allowed offset for an address in the LD command */
 #define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
@@ -88,6 +91,9 @@ static struct machine_function * avr_ini
 static rtx avr_builtin_setjmp_frame_value (void);
 static bool avr_hard_regno_scratch_ok (unsigned int);
 
+static void avr_init_builtins_hook (void);
+static rtx avr_expand_builtin_hook (tree, rtx, rtx, enum machine_mode mode, int);
+
 /* Allocate registers from r25 to r8 for parameters for function calls.  */
 #define FIRST_CUM_REG 26
 
@@ -357,6 +363,12 @@ int avr_case_values_threshold = 30000;
 #undef TARGET_HARD_REGNO_SCRATCH_OK
 #define TARGET_HARD_REGNO_SCRATCH_OK avr_hard_regno_scratch_ok
 
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS avr_init_builtins_hook
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN avr_expand_builtin_hook
+
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 void
@@ -6103,4 +6115,112 @@ avr_return_in_memory (const_tree type, c
     return false;
 }
 
+
+enum avr_builtin_id
+{
+    AVR_BUILTIN_PGM_READ_BYTE,
+    
+    AVR_BUILTIN_MAX
+};
+
+enum avr_ftype_id
+{
+    AVR__UNSIGNED_CHAR__FTYPE__CONST_UNSIGNED_CHAR_PTR,
+    
+    AVR_FTYPE_MAX
+};
+
+static GTY(()) tree avr_builtin_decls[(int) AVR_BUILTIN_MAX];
+static GTY(()) tree avr_ftypes[(int) AVR_FTYPE_MAX];
+
+static struct avr_builtin_description
+{
+    const enum insn_code icode;
+    const enum avr_ftype_id ftype;
+    const char * const name;
+}
+avr_builtins [AVR_BUILTIN_MAX] =
+{
+    [AVR_BUILTIN_PGM_READ_BYTE] =
+    {
+        .icode = CODE_FOR_pgm_read_byte,
+        .ftype = AVR__UNSIGNED_CHAR__FTYPE__CONST_UNSIGNED_CHAR_PTR,
+        .name  = "__builtin_pgm_read_byte"
+    }
+};
+
+static void
+avr_init_ftypes (void)
+{
+    /* const unsigned char *  */
+    tree const_unsigned_char_ptr_type_node
+        = build_pointer_type (build_type_variant (unsigned_char_type_node, 1, 0));
+
+    /* unsigned char (*) (const unsigned char*) */
+    avr_ftypes[(int) AVR__UNSIGNED_CHAR__FTYPE__CONST_UNSIGNED_CHAR_PTR]
+        = build_function_type_list (unsigned_char_type_node, const_unsigned_char_ptr_type_node, NULL_TREE);
+}
+
+static void
+avr_init_builtins_hook (void)
+{
+    int id;
+    struct avr_builtin_description * d = avr_builtins;
+
+    avr_init_ftypes ();
+        
+    for (id = 0; id < (int) AVR_BUILTIN_MAX; id++, d++)
+    {
+        avr_builtin_decls[id]
+            = add_builtin_function (d->name, avr_ftypes[d->ftype], id,
+                                    BUILT_IN_MD, NULL, NULL_TREE);
+    }
+}
+
+/* Expand an expression EXP that calls a built-in function, with result going
+   to TARGET if that's convenient (and in mode MODE if that's convenient).
+   SUBTARGET may be used as the target for computing one of EXP's operands.
+   IGNORE is nonzero if the value is to be ignored. */
+static rtx
+avr_expand_builtin_hook (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
+                    enum machine_mode mode ATTRIBUTE_UNUSED,
+                    int ignore ATTRIBUTE_UNUSED)
+{
+    enum insn_code icode;
+    tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+    tree arg1;
+    rtx op1, pat;
+    enum machine_mode mode1;
+    unsigned int id = DECL_FUNCTION_CODE (fndecl);
+
+    icode = avr_builtins[id].icode;
+    
+    switch (id)
+    {
+        case AVR_BUILTIN_PGM_READ_BYTE:
+
+            arg1  = CALL_EXPR_ARG (exp, 0);
+            mode1 = insn_data[icode].operand[1].mode;
+            
+            op1 = expand_normal (arg1);
+            op1 = force_reg (Pmode, op1);
+
+            if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
+                op1 = copy_to_mode_reg (mode1, op1);
+            
+            pat = GEN_FCN (icode) (target, op1);
+            break;
+
+        default:
+            abort();
+    }
+
+    if (!pat)
+        return NULL_RTX;
+
+    emit_insn (pat);
+    
+    return target;
+}
+
 #include "gt-avr.h"
Index: gcc/config/avr/avr.opt
===================================================================
--- gcc/config/avr/avr.opt	(revision 143546)
+++ gcc/config/avr/avr.opt	(working copy)
@@ -66,3 +66,6 @@ Relax branches
 mpmem-wrap-around
 Target Report
 Make the linker relaxation machine assume that a program counter wrap-around occures.
+
+mtest=
+Target RejectNegative Report Joined Undocumented UInteger Var(avr_test) Init(0)
