User:Gso321/GCC/Frontend/Hello world

From Gentoo Wiki
Jump to:navigation Jump to:search

Before starting, the following is required: dev-vcs/git, internet connection, and around 3 GB of free disk space. The example language name will be "Opus". Any references to any language with the name "Opus" are purely coincidental.

Setting GCC up

user $git clone git://gcc.gnu.org/git/gcc.git gcc-src
user $mkdir gcc-build
user $cd gcc-src

This grabs the GCC source code into gcc-src directory, which may take a while depending on the speed of the system’s internet speed. Then make the gcc-build directory, which is where GCC build will happen.

Make sure GCC has requirements to compile itself:

user $./contrib/download_prerequisites

Add the opus directory and change into gcc/opus directory for the language (This is the main directory for an language):

user $mkdir gcc/opus
user $cd gcc/opus

Required files

When creating a language, GCC expects some files to be presented. In this example, it would be config-lang.in, Make-lang.in, lang-specs.h, opus-lang.cc, and opusspec.cc.

config-lang.in

FILE config-lang.in
language="opus"
compilers="opus1\$(exeext)"

build_by_default="no"

gtfiles="\$(srcdir)/opus/opus-lang.cc"
Note
See this for more information.

The language specifies the name of language as it would appear in $(LANGUAGES). The compilers specifies the internal language compiler to use in $(COMPILERS). The \$(exeext) expands to .exe when using Windows OS, meant to make it executable for the Windows OS. The build_by_default with "no" means GCC needs to have —-enable-languages=opus in order for GCC to compile opus files. gtfiles relates to this link.

lang-specs.h

FILE lang-specs.h
{".opus", "@opus", 0, 1, 0},
{"@opus",
"opus1 %i %(cc1_options) %{I*} %{L*} %D %{!fsyntax-only:%(invoke_as)}", 0, 1,
0},

In this lang-specs.h header file, it directs files ending with .opus in line 1 to the opus1 compiler via %i (%i, like C's printf, is replaced with the .opus files) in line 2.

Make-lang.in

FILE Make-lang.in
GCCOPUS_INSTALL_NAME := $(shell echo gccopus|sed '$(program_transform_name)')
GCCOPUS_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gccopus|sed '$(program_transform_name)')

opus: opus1$(exeext)
opus.serial = opus1$(exeext)

.PHONY: opus

# Driver

GCCOPUS_OBJS = \
   $(GCC_OBJS) \
   opus/opusspec.o \
   $(END)

gccopus$(exeext): $(GCCOPUS_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS)
	+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
	  $(GCCOPUS_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \
	  $(EXTRA_GCC_LIBS) $(LIBS)

# The compiler proper

opus_OBJS = \
    opus/opus-lang.o \
    $(END)

opus1$(exeext): attribs.o $(opus_OBJS) $(BACKEND) $(LIBDEPS) $(opus.prev)
	@$(call LINK_PROGRESS,$(INDEX.opus),start)
	+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
	      attribs.o $(opus_OBJS) $(BACKEND) $(LIBS) $(BACKENDLIBS)
	@$(call LINK_PROGRESS,$(INDEX.opus),end)

opus.all.cross:

opus.start.encap: gccopus$(exeext)
opus.rest.encap:

opus.install-common: installdirs
	-rm -f $(DESTDIR)$(bindir)/$(GCCOPUS_INSTALL_NAME)$(exeext)
	$(INSTALL_PROGRAM) gccopus$(exeext) $(DESTDIR)$(bindir)/$(GCCOPUS_INSTALL_NAME)$(exeext)
	rm -f $(DESTDIR)$(bindir)/$(GCCOPUS_TARGET_INSTALL_NAME)$(exeext); \
	( cd $(DESTDIR)$(bindir) && \
      $(LN) $(GCCOPUS_INSTALL_NAME)$(exeext) $(GCCOPUS_TARGET_INSTALL_NAME)$(exeext) ); \

# Required goals, they still do nothing
opus.install-man:
opus.install-info:
opus.install-pdf:
opus.install-plugin:
opus.install-html:
opus.info:
opus.dvi:
opus.pdf:
opus.html:
opus.man:
opus.mostlyclean:
opus.clean:
opus.distclean:
opus.maintainer-clean:
selftest-opus:

# make uninstall
opus.uninstall:
	-rm -f gccopus$(exeext) opus1$(exeext)
	-rm -f $(opus_OBJS)

# Used for handling bootstrap
opus.stage1: stage1-start
	-mv opus/*$(objext) stage1/opus
opus.stage2: stage2-start
	-mv opus/*$(objext) stage2/opus
opus.stage3: stage3-start
	-mv opus/*$(objext) stage3/opus
opus.stage4: stage4-start
	-mv opus/*$(objext) stage4/opus
opus.stageprofile: stageprofile-start
	-mv opus/*$(objext) stageprofile/opus
opus.stagefeedback: stagefeedback-start
	-mv opus/*$(objext) stagefeedback/opus

opusspec.cc

FILE opusspec.cc
void
lang_specific_driver (struct cl_decoded_option ** /* in_decoded_options */,
		      unsigned int * /* in_decoded_options_count */,
		      int * /*in_added_libraries */)
{
}

/* Called before linking.  Returns 0 on success and -1 on failure.  */
int
lang_specific_pre_link (void)
{
  /* Not used for Opus.  */
  return 0;
}

/* Number of extra output files that lang_specific_pre_link may generate.  */
int lang_specific_extra_outfiles = 0; /* Not used for Opus.  */

opus-lang.cc

FILE opus-lang.cc
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "target.h"
#include "tree.h"
#include "gimple-expr.h"
#include "diagnostic.h"
#include "opts.h"
#include "fold-const.h"
#include "gimplify.h"
#include "stor-layout.h"
#include "debug.h"
#include "convert.h"
#include "langhooks.h"
#include "langhooks-def.h"
#include "common/common-target.h"

#include <mpfr.h>

/* Language-dependent contents of a type.  */

struct GTY (()) lang_type
{
  char dummy;
};

/* Language-dependent contents of a decl.  */

struct GTY (()) lang_decl
{
  char dummy;
};

/* Language-dependent contents of an identifier.  This must include a
   tree_identifier.  */

struct GTY (()) lang_identifier
{
  struct tree_identifier common;
};

/* The resulting tree type.  */

union GTY ((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
	    chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), "
			"TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN "
			"(&%h.generic)) : NULL"))) lang_tree_node
{
  union tree_node GTY ((tag ("0"), desc ("tree_node_structure (&%h)"))) generic;
  struct lang_identifier GTY ((tag ("1"))) identifier;
};

/* We don't use language_function.  */

struct GTY (()) language_function
{
  int dummy;
};

/* Language hooks.  */

static bool
opus_langhook_init (void)
{
  build_common_tree_nodes (false);
  void_list_node = build_tree_list (NULL_TREE, void_type_node);
  build_common_builtin_nodes ();
  return true;
}

/* The main function of the frontend */

static void
opus_langhook_parse_file (void)
{
  fprintf(stderr, "Hello world!\n");
}

static tree
opus_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
{
  if (mode == TYPE_MODE (float_type_node))
    return float_type_node;

  if (mode == TYPE_MODE (double_type_node))
    return double_type_node;

  if (mode == TYPE_MODE (intQI_type_node))
    return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
  if (mode == TYPE_MODE (intHI_type_node))
    return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
  if (mode == TYPE_MODE (intSI_type_node))
    return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
  if (mode == TYPE_MODE (intDI_type_node))
    return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
  if (mode == TYPE_MODE (intTI_type_node))
    return unsignedp ? unsigned_intTI_type_node : intTI_type_node;

  if (mode == TYPE_MODE (integer_type_node))
    return unsignedp ? unsigned_type_node : integer_type_node;

  if (mode == TYPE_MODE (long_integer_type_node))
    return unsignedp ? long_unsigned_type_node : long_integer_type_node;

  if (mode == TYPE_MODE (long_long_integer_type_node))
    return unsignedp ? long_long_unsigned_type_node
		     : long_long_integer_type_node;

  if (COMPLEX_MODE_P (mode))
    {
      if (mode == TYPE_MODE (complex_float_type_node))
	return complex_float_type_node;
      if (mode == TYPE_MODE (complex_double_type_node))
	return complex_double_type_node;
      if (mode == TYPE_MODE (complex_long_double_type_node))
	return complex_long_double_type_node;
      if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
	return complex_integer_type_node;
    }

  /* gcc_unreachable */
  return NULL;
}

static tree
opus_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED,
			     int unsignedp ATTRIBUTE_UNUSED)
{
  gcc_unreachable ();
  return NULL;
}

/* Record a builtin function.  We just ignore builtin functions.  */

static tree
opus_langhook_builtin_function (tree decl)
{
  return decl;
}

static bool
opus_langhook_global_bindings_p (void)
{
  gcc_unreachable ();
  return true;
}

static tree
opus_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
{
  gcc_unreachable ();
}

static tree
opus_langhook_getdecls (void)
{
  return NULL;
}

tree
convert (tree type, tree expr)
{
  if (type == error_mark_node
      || expr == error_mark_node
      || TREE_TYPE (expr) == error_mark_node)
    return error_mark_node;

  if (type == TREE_TYPE (expr))
    return expr;

  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
    return fold_convert (type, expr);

  switch (TREE_CODE (type))
    {
    case VOID_TYPE:
    case BOOLEAN_TYPE:
      return fold_convert (type, expr);
    case INTEGER_TYPE:
      return fold (convert_to_integer (type, expr));
    case POINTER_TYPE:
      return fold (convert_to_pointer (type, expr));
    case REAL_TYPE:
      return fold (convert_to_real (type, expr));
    case COMPLEX_TYPE:
      return fold (convert_to_complex (type, expr));
    default:
      break;
    }

  gcc_unreachable ();
}

#undef LANG_HOOKS_NAME
#undef LANG_HOOKS_INIT
#undef LANG_HOOKS_PARSE_FILE
#undef LANG_HOOKS_TYPE_FOR_MODE
#undef LANG_HOOKS_TYPE_FOR_SIZE
#undef LANG_HOOKS_BUILTIN_FUNCTION
#undef LANG_HOOKS_GLOBAL_BINDINGS_P
#undef LANG_HOOKS_PUSHDECL
#undef LANG_HOOKS_GETDECLS

#define LANG_HOOKS_NAME "GNU Opus"
#define LANG_HOOKS_INIT opus_langhook_init
#define LANG_HOOKS_PARSE_FILE opus_langhook_parse_file
#define LANG_HOOKS_TYPE_FOR_MODE opus_langhook_type_for_mode
#define LANG_HOOKS_TYPE_FOR_SIZE opus_langhook_type_for_size
#define LANG_HOOKS_BUILTIN_FUNCTION opus_langhook_builtin_function
#define LANG_HOOKS_GLOBAL_BINDINGS_P opus_langhook_global_bindings_p
#define LANG_HOOKS_PUSHDECL opus_langhook_pushdecl
#define LANG_HOOKS_GETDECLS opus_langhook_getdecls

struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;

#include "gt-opus-opus-lang.h"
#include "gtype-opus.h"

GCC with Opus support

user $cd ../../../gcc-build
user $../gcc-src/configure --prefix=$(pwd)/../gcc-install --disable-bootstrap --enable-languages=c,c++,opus
user $make -j9
user $make install -j9

Change to GCC build directory and compile GCC there. —-disable-bootstrap —-enable-languages compiles GCC only once and allows GCC to compile C,C++,Opus programs. See these configuration options for more information.

Finally, make sure gcc executes opus1 when it sees .opus files:

user $cd ../gcc-install/bin
user $touch main.opus
user $./gcc main.opus -c
Hello world!