rubikwizard
Posts: 95
Joined: Tue Jan 10, 2012 10:37 pm
Location: West Yorkshire
Contact: Website

Compiling Amiga code with GCC

Tue Aug 09, 2016 9:41 pm

In the late 1980s I used the Lattice C compiler on an Amiga to make various programs that required the use of a math parser. I obtained the code for a math parser from a Fred Fish public domain disk (number 92) which worked perfectly and compiled without issue.

Having not used C since that time I am now rekindling my interest with the Raspberry Pi and can successfully write small programs using GCC, although I seem to have forgotten all of my C knowledge so am re-learning it (slowly!)

I would like to make use of this math parser once again but I am struggling to get it to compile successfully under GCC, presumably due to standards changing over time.

The first issue is #include <functions.h>, which is not found so I have removed this line and also added in #include <string.h> which seems to clear up quite a few problems, but I am stuck what to do next.

I would be really grateful if anyone could take a look, and maybe try compiling it and give me some pointers as to what the issues might be. I have put the original code below.

Many thanks
Neil

Code: Select all

/********************************************************************
 * Parse.c (C) copyright 1987 John M. Olsen
 *
 * /|  |    /|||  /\|		|	John M. Olsen
 * \|()|\|\_ |||. \/|/)@|\_	|	1547 Jamestown Drive
 *  |				|	Salt Lake City, UT  84121-2051
 * u-jmolse@ug.utah.edu  or  ...!{seismo,ihnp4}!utah-cs!utah-ug!u-jmolse
 *
 * This program or any significant portion of it may not be used in a
 * commercial product without written permission of the author.  (My
 * permission is easy to get).
 *
 * Feel free to distribute this code as part of any public domain collection,
 * or hack on it to make it more user friendly, as long as you try to
 * document your changes as not being my code.
 *
 * This is a recursive descent exprsession parser, based very loosely on one
 * found in Herbert Schildt's book "Advanced C", published by McGraw-Hill.
 * It parses expressions by having each layer either recognize something that
 * it can do, or passing it on to the next function which does higher
 * precedence operators.
 *
 * It has very minimal error checking, and does not check for overflow or
 * underflow on calculations.  If it detects an error, it will give a message
 * and what it thinks the correct result was up to that time.
 *
 * It converts expressions to lower case so it only needs to look for math
 * function names spelled one way.
 *
 * It uses standard I/O, so it must be used from the CLI.  This makes it
 * very easy to port to other machines.
 *
 * Aztec instructions using fast floating point:
 *
 * cc parse.c
 * ln parse.o -lm -lc
 *
 * Aztec 4.30a using IEEE double precision floating point: (Big difference!)
 *
 * cc parse.c +fi
 * ln parse.o -lmx -lc
 *
 * It has also been (fairly) successfully compiled on a VAX1180, but it
 * complained at expressions on the argument list.  The only modification
 * required was to comment out the #include <functions.h> command.
 *
 *********************************************************************/

#include <stdio.h>
#include <ctype.h>
#include <functions.h>
#include <math.h>

#define PI ((double)3.14159265358979)
#define E  ((double)2.71828182845904)

#define TOK_SIZE 20	/* Tokens are no longer than this number. */
#define EXP_SIZE 80	/* Expressions no longer than this number. */

#define TRUE 1
#define FALSE 0

extern double atof(), binary(), fn_eval();
extern double parse(), parse2(), parse3(), parse4(), parse5();

/* Here is a simple calling program to test it. */

main (argc, argv)
int argc;
char *argv[];
{
	char exprs[EXP_SIZE];
	double ans;
	int loop;

	if(argc < 2)
	{
		ans = 0;
		printf("Type '?' for help.\n");
		printf("Enter exprsression: ");
		gets (exprs);
	}
	else
	{
		exprs[0] = NULL;
		for(loop = 1; loop < argc; loop++)
			strcat(exprs, argv[loop]);
	}
	for(loop = 0; loop < strlen(exprs); loop++) /* convert to lower case */
		if(isalpha(exprs[loop]))
			exprs[loop] = tolower(exprs[loop]);
	if(exprs[0] == '?' || exprs[0] == 'h')
	{	/* help menu */
		printf("Supported binary operators: + - / % ^\n");
		printf("Supported unary operators:  + -\n");
		printf("Supported unary functions:  sin, cos, tan,\n");
		printf("	asin, acos, atan, sinh, cosh, tahn,\n");
		printf("	log, logten, abs, sqrt, int.\n");
		printf("Defined constants:          pi, e.\n\n");
		printf("Usage: %s (expression)\n", argv[0]);
		printf("   or: %s ?\n", argv[0]);
		exit(0);
	}
	ans = parse (exprs);
	if(exprs[0])
		printf("Bad expression.\n");
	else
		printf ("%f\n", ans);
}

/*******************************************************************
The main parser function. It parses + and -.
*******************************************************************/
double parse (exprs)
char exprs[];
{
	char tok[TOK_SIZE];	/* this should only be a + or - character. */
	double a;

	a = parse2 (exprs);
	while (exprs[0])
	{
		get_token (tok, exprs);
		if (tok[0] == '+' || tok[0] == '-')
			a = binary (a, parse2 (exprs), tok);
		else
			return (a);
	}
	return (a);
}

/*******************************************************************
The secondary parser, which parses * and /.
*******************************************************************/
double parse2 (exprs)
char *exprs;
{
	char tok[TOK_SIZE];
	double a;

	a = parse3 (exprs);
	while (exprs[0])
	{
		get_token (tok, exprs);
		if (tok[0] == '*' || tok[0] == '/' || tok[0] == 'm'
					 || tok[0] == 'd')
			a = binary (a, parse3 (exprs), tok);
		else
		{
			unget_tok (tok, exprs);
			return (a);
		}	
	}
	return (a);
}

/*******************************************************************
The third parser, which parses ^.
*******************************************************************/
double parse3 (exprs)
char *exprs;
{
	char tok[TOK_SIZE];
	double a;

	a = parse4 (exprs);
	while (exprs[0])
	{
		get_token (tok, exprs);
		if (tok[0]=='^')
			a = (binary (a, parse4 (exprs), tok));
		else
		{
			unget_tok (tok, exprs);
			return (a);
		}	
	}
	return (a);
}

/*******************************************************************
The fourth parser, which parses unary minus and plus.
*******************************************************************/
double parse4 (exprs)
char *exprs;
{
	char tok[TOK_SIZE];

	get_token (tok, exprs);
	if (tok[0] == '-')
		return (-(parse4 (exprs)));
	else if(tok[0] == '+')
		return(parse4(exprs));
	unget_tok (tok, exprs);
	return (parse5 (exprs));
}

/*******************************************************************
The fifth parser, which parses functions and parentheses.
*******************************************************************/
double parse5 (exprs)
char *exprs;
{
	char tok[TOK_SIZE], buff[EXP_SIZE];
	double a;

	get_fn (tok, exprs);
	if (tok[0])	/* a function call. */
		return (fn_eval (tok, exprs));
	get_numb (tok, exprs);
	if (tok[0])	/* A number. */
		return (atof (tok));
	if (exprs[0] == '(')	/* a parenthesized exprsression. */
	{	/*strip open paren, call parse, strip close paren. */
		strcpy (buff, exprs + 1);
		strcpy (exprs, buff);
		a = parse (exprs);
		if (exprs[0] == ')')
		{
			strcpy (buff, exprs + 1);
			strcpy (exprs, buff);
		}
		else
		{	/* Error if here. */
			printf("Bad parentheses.\n");
		}
		return (a);
	}
	printf("Bad parentheses.\n");
}

/*******************************************************************
Return a pointer to a string with the token in it.  A token may be
at most TOK_SIZE characters.  All after that are tossed into the
bit bucket.
*******************************************************************/
get_token (tok, exprs)
char *tok, *exprs;
{
	char temp[EXP_SIZE];

	tok[0] = 0;
	while (iswhite (exprs[0]))	/* move from exprs[1] to exprs[0] */
	{
		strcpy (temp, exprs + 1);
		strcpy (exprs, temp);
	}
	sscanf (exprs, "%1[+-*/^]", tok);
	strcpy (temp, exprs + strlen (tok));
	strcpy (exprs, temp);
}

/*******************************************************************
Get a number from the front of the exprsression.
*******************************************************************/
get_numb (tok, exprs)
char *tok, *exprs;
{
	char temp[EXP_SIZE];

	tok[0] = 0;
	while (iswhite (exprs[0]))	/* move from exprs[1] to exprs[0] */
	{
		strcpy (temp, exprs + 1);
		strcpy (exprs, temp);
	}
	sscanf (exprs, "%[0123456789.]", tok);
	strcpy (temp, exprs + strlen (tok));
	strcpy (exprs, temp);
}
/*******************************************************************
Get a function name from the front of the exprsression.
*******************************************************************/
get_fn (tok, exprs)
char *tok, *exprs;
{
	char temp[EXP_SIZE];

	tok[0] = 0;
	while (iswhite (exprs[0]))	/* move from exprs[1] to exprs[0] */
	{
		strcpy (temp, exprs + 1);
		strcpy (exprs, temp);
	}
	sscanf (exprs, "%[abcdefghijklmnopqrstuvwxyz]", tok);
	strcpy (temp, exprs + strlen (tok));
	strcpy (exprs, temp);
}

/*******************************************************************
Replace a token at the front of the exprsression.
*******************************************************************/
unget_tok (tok, exprs)
char *tok, *exprs;
{
	char buff[EXP_SIZE];

	strcpy (buff, exprs);
	strcpy (exprs, tok);
	strcat (exprs, buff);
}

/*******************************************************************
This fn returns true if the key given to it is white space.
*******************************************************************/
iswhite (key)
char key;
{
	if (key == ' ' || key == 9 || key == 13)
		return (1);
	return (0);
}
/*******************************************************************
This fn returns (a operator b), or just a if an error occurs.
*******************************************************************/
double binary (a, b, tok)
double a, b;
char *tok;
{
	int loop;
	double c;

	switch (tok[0])
	{
		case '+':
			return (a + b);
		case '-':
			return (a - b);
		case '*':
			return (a * b);
		case '/':
			if (!near_zero (b))	/* if b != 0 */
				return (a / b);
			else
			{	/* division by zero error message. */
				printf("Division by zero error.\n");
			}
			return (a);
		case '^':	/* a to the b power. */
		{
			c = a;
			if (near_zero (b))	
				return (a);
			return(pow(a,b));
			/* non-function if you don't like the pow function */
			for (loop = (int) b - 1;loop > 0; --loop)
				a = a * c;
			return (a);
		}
		default:
			printf("No such token as %c\n", tok[0]);
	}
}

/*******************************************************************
Evaluates the function on the front of exprs.
*******************************************************************/
double fn_eval (tok, exprs)
char *exprs, *tok;
{
	if (tok[0])
	{
		if (!strcmp(tok, "abs"))
			return(fabs (parse5(exprs)));
		if (!strcmp(tok, "sqrt"))
			return(sqrt (parse5(exprs)));
		if (!strcmp(tok, "tan"))
			return(tan (parse5(exprs)));
		if (!strcmp(tok, "sin"))
			return(sin (parse5(exprs)));
		if (!strcmp(tok, "cos"))
			return(cos (parse5(exprs)));
		if (!strcmp(tok, "atan"))
			return(atan (parse5(exprs)));
		if (!strcmp(tok, "asin"))
			return(asin (parse5(exprs)));
		if (!strcmp(tok, "acos"))
			return(acos (parse5(exprs)));
		if (!strcmp(tok, "tanh"))
			return(tanh (parse5(exprs)));
		if (!strcmp(tok, "sinh"))
			return(sinh (parse5(exprs)));
		if (!strcmp(tok, "cosh"))
			return(cosh (parse5(exprs)));
		if (!strcmp(tok, "pi"))
			return(PI);
		if (!strcmp(tok, "e"))
			return(E);
		if (!strcmp(tok, "log"))
			return(log(parse5(exprs)));
		if (!strcmp(tok, "logten"))
			return(log10(parse5(exprs)));
		if (!strcmp(tok, "int"))
			return((double)((long)(parse5(exprs))));
	}
	printf("Could not find expression %s\n",tok);
	unget_tok(tok, exprs);
}

/*******************************************************************
Returns true if num is near zero. It's used in division checks.
*******************************************************************/
near_zero (num)
double num;
{
	if (fabs (num) < .000000001)
		return (1);
	return (0);
}


User avatar
AndyD
Posts: 2333
Joined: Sat Jan 21, 2012 8:13 am
Location: Melbourne, Australia
Contact: Website

Re: Compiling Amiga code with GCC

Wed Aug 10, 2016 8:51 am

With the modifications you suggest, you can compile and run your program. It is pre-ANSI C, so you will get a number of warnings.

To compile and run use:-

Code: Select all

gcc Parse.c -o parse
./parse

rubikwizard
Posts: 95
Joined: Tue Jan 10, 2012 10:37 pm
Location: West Yorkshire
Contact: Website

Re: Compiling Amiga code with GCC

Wed Aug 10, 2016 10:08 am

Thanks for this Andy.
I have done exactly what you said, but no executable is produced. The output from the command you gave to compile is shown below. Any ideas?

Code: Select all

parser.c: In function ‘main’:
parser.c:81:7: warning: ‘gets’ is deprecated (declared at /usr/include/stdio.h:638) [-Wdeprecated-declarations]
       gets (exprs);
       ^
parser.c:85:16: warning: assignment makes integer from pointer without a cast
       exprs[0] = NULL;
                ^
parser.c:102:7: warning: incompatible implicit declaration of built-in function ‘exit’
       exit(0);
       ^
/tmp/ccWA62Za.o: In function `main':
parser.c:(.text+0x44): warning: the `gets' function is dangerous and should not be used.
/tmp/ccWA62Za.o: In function `binary':
parser.c:(.text+0x980): undefined reference to `pow'
/tmp/ccWA62Za.o: In function `fn_eval':
parser.c:(.text+0xa2c): undefined reference to `sqrt'
parser.c:(.text+0xa60): undefined reference to `tan'
parser.c:(.text+0xa94): undefined reference to `sin'
parser.c:(.text+0xac8): undefined reference to `cos'
parser.c:(.text+0xafc): undefined reference to `atan'
parser.c:(.text+0xb30): undefined reference to `asin'
parser.c:(.text+0xb64): undefined reference to `acos'
parser.c:(.text+0xb98): undefined reference to `tanh'
parser.c:(.text+0xbcc): undefined reference to `sinh'
parser.c:(.text+0xc00): undefined reference to `cosh'
parser.c:(.text+0xc74): undefined reference to `log'
parser.c:(.text+0xca8): undefined reference to `log10'
collect2: error: ld returned 1 exit status

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 7895
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: Compiling Amiga code with GCC

Wed Aug 10, 2016 10:24 am

Code: Select all

gcc Parse.c -o parse -lm
to link in the maths library that implements pow, sqrt, etc.
I do still get a couple of warnings

Code: Select all

parse.c: In function main:
parse.c:86: warning: assignment makes integer from pointer without a cast
parse.c:95: warning: unknown conversion type character ^ in format
parse.c:103: warning: incompatible implicit declaration of built-in function exit
A fixed up version of main() reads

Code: Select all

main (argc, argv)
int argc;
char *argv[];
{
   char exprs[EXP_SIZE];
   double ans;
   int loop;

   if(argc < 2)
   {
      ans = 0;
      printf("Type '?' for help.\n");
      printf("Enter exprsression: ");
      gets (exprs);
   }
   else
   {
      exprs[0] = '\0';
      for(loop = 1; loop < argc; loop++)
         strcat(exprs, argv[loop]);
   }
   for(loop = 0; loop < strlen(exprs); loop++) /* convert to lower case */
      if(isalpha(exprs[loop]))
         exprs[loop] = tolower(exprs[loop]);
   if(exprs[0] == '?' || exprs[0] == 'h')
   {   /* help menu */
      printf("Supported binary operators: + - / %% ^\n");
      printf("Supported unary operators:  + -\n");
      printf("Supported unary functions:  sin, cos, tan,\n");
      printf("   asin, acos, atan, sinh, cosh, tahn,\n");
      printf("   log, logten, abs, sqrt, int.\n");
      printf("Defined constants:          pi, e.\n\n");
      printf("Usage: %s (expression)\n", argv[0]);
      printf("   or: %s ?\n", argv[0]);
      return(0);
   }
   ans = parse (exprs);
   if(exprs[0])
      printf("Bad expression.\n");
   else
      printf ("%f\n", ans);
}
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

rubikwizard
Posts: 95
Joined: Tue Jan 10, 2012 10:37 pm
Location: West Yorkshire
Contact: Website

Re: Compiling Amiga code with GCC

Wed Aug 10, 2016 10:43 am

@6by9
Wow! Thank you very much for this, much appreciated!

I know I am being really dumb but why is the option -lm required when we already have #include <math.h> ?

Thanks again
Neil

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 7895
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: Compiling Amiga code with GCC

Wed Aug 10, 2016 10:51 am

rubikwizard wrote:I know I am being really dumb but why is the option -lm required when we already have #include <math.h> ?
An include gives the prototypes for the functions contained in the library, not an implementation. The linker needs to be told how to find the implementation, hence the -l.

There are several ways that libraries are linked in. Some can be done dynamically at runtime (known as either a Dynamic Link Library (DLL) under Windows, or Shared Object (.so file) under Linux), which means the library can be installed once on the system and reused again and again. As long as the prototypes don't change, it also allows the library to be updated without needing to rebuild any application using it.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

rubikwizard
Posts: 95
Joined: Tue Jan 10, 2012 10:37 pm
Location: West Yorkshire
Contact: Website

Re: Compiling Amiga code with GCC

Wed Aug 10, 2016 11:03 am

Thanks for the explanation. I think I understand!

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Compiling Amiga code with GCC

Sun Aug 28, 2016 12:11 am

Get a reference on ANSI C, like The C Programming Language, Second Edition, ANSI C by Brian W Kernighan and Dennis M Ritchie. IT is worth it if you are accustomed to Lattice C.

I got the book a few years ago (2000 or 2001), as I was accustomed to the old Pure C on the Atari ST series. I had not used C on RISC OS until fairly recently (around 2001).

I would like to see a decent compiler for K&R C (C as it was before ANSI C) on modern systems. While the modern compilers will support K&R C for the most part, they throw so many warnings that it makes it very difficult to read the output notices.

I would also like to see a C compiler that has a good implementation of inline assembly, not this GNU method that makes little to no since.

Though it should not be to hard to get going on C programming again.
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

jahboater
Posts: 5027
Joined: Wed Feb 04, 2015 6:38 pm

Re: Compiling Amiga code with GCC

Sun Aug 28, 2016 4:32 pm

DavidS wrote:I would also like to see a C compiler that has a good implementation of inline assembly, not this GNU method that makes little to no sense.
GCC inline assembler is wonderful! There is, it is true, a long and steep learning curve, but the benefits are worth it. You can specify exactly what you want to do and what the side effects are, which means the asm can be fully included within the surrounding C code optimization. Otherwise with a simpler scheme, the compiler has to save and restore ALL the registers and switch off optimization because it has no idea what the asm is doing or what its side effects might be.

New features like the ability to export the flags are really cool, and I have not seen anything similar elsewhere.

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Compiling Amiga code with GCC

Sun Aug 28, 2016 5:52 pm

jahboater wrote:
DavidS wrote:I would also like to see a C compiler that has a good implementation of inline assembly, not this GNU method that makes little to no sense.
GCC inline assembler is wonderful! There is, it is true, a long and steep learning curve, but the benefits are worth it. You can specify exactly what you want to do and what the side effects are, which means the asm can be fully included within the surrounding C code optimization. Otherwise with a simpler scheme, the compiler has to save and restore ALL the registers and switch off optimization because it has no idea what the asm is doing or what its side effects might be.

New features like the ability to export the flags are really cool, and I have not seen anything similar elsewhere.
No no. It is the responcibility of the inline assembly to preserve and restore any registers that are used. The only integration should be access to veriables in a simple way. That is using variable names to represent offsets of R13 for those on the stack, and using veriable names/function names to represent the address at which other veriables/functions are located, as well as using #define constants (though that is done by the preprocessor).

Having the compiler attempt to do the rest is bad form, and limiting.
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

User avatar
Paeryn
Posts: 2805
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Compiling Amiga code with GCC

Sun Aug 28, 2016 6:18 pm

DavidS wrote: No no. It is the responcibility of the inline assembly to preserve and restore any registers that are used. The only integration should be access to veriables in a simple way. That is using variable names to represent offsets of R13 for those on the stack, and using veriable names/function names to represent the address at which other veriables/functions are located, as well as using #define constants (though that is done by the preprocessor).

Having the compiler attempt to do the rest is bad form, and limiting.
Why should the inline asm have to preserve registers? With gcc's methos the compiler can determine whether it needs to preserve the registers you say your code clobbers, it may be that the compiler can arrange it's code so that it doesn't need to.

As to variables on the stack/elsewhwere in memory, what if the variables aren't stored in memory? Sometimes the compiler can completely eliminate the need to ever store a variable in anything other than a register.
She who travels light — forgot something.

jahboater
Posts: 5027
Joined: Wed Feb 04, 2015 6:38 pm

Re: Compiling Amiga code with GCC

Sun Aug 28, 2016 7:16 pm

Paeryn wrote:Why should the inline asm have to preserve registers? With gcc's methos the compiler can determine whether it needs to preserve the registers you say your code clobbers, it may be that the compiler can arrange it's code so that it doesn't need to.
Exactly. And for a RISC machine with a lot of registers (31 on ARM 64) it never in practice needs to save any. The compiler is simply aware that the registers you have said are clobbered will lose any value held in them and avoid using them. But with a simpler inline asm system where you cant specify those clobbered registers, it must save and restore all of them :evil:
Paeryn wrote: As to variables on the stack/elsewhwere in memory, what if the variables aren't stored in memory? Sometimes the compiler can completely eliminate the need to ever store a variable in anything other than a register.
With the gcc asm contraints YOU get to choose exactly where you want your variable when the asm starts using it; as an immediate if its a literal, in memory, in a register, in the constant pool, in a VFP register, or best, anywhere, as it lets the compiler decide, and so on - there are lots and lots of options.

For RISC, you mostly want the variable in a register in order to do anything with it, that's the nature of RISC. You cant do "add r1,mmm" like you can on x86, it has to be "add r1,r2".

To add one to a variable for example:

int counter;
asm( "add %0,%0,#1" : "+r" (counter) )

It doesn't matter where counter is stored (most likely in a register already, but it could be on the stack in which case the compiler will add the ldr and str instructions as needed).

Here is another simple example to clear the floating point exceptions:

asm( "vmsr fpscr,%0" :: "r" (0) )

vmsr only takes a register. Gcc will choose a spare register and load zero into it for you. No other registers get saved or restored, there is no need.
The asm also specifies that the register is read only so it will still have zero in it afterwards and can be used again elsewhere. If you called this asm twice in succession for example it would only zero the register before the first one. Its all about fitting in with the compilers optimisation.

A poor example would be

asm( "mov r1,#0; vmsr fpscr,r1" ::: "r1" )

Here the compiler cannot use the zero'd register for anything else, or re-use a register that it happens to know already has zero in it.
It does know that anything in r1 will be lost, so the register allocator will have to re-arrange things so as not to use r1 at that point. The prior example was better because the register allocation was not affected at all.

This gnu inline asm system is used by all three major compilers Intel ICC, LLVM, and of course GCC.

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Compiling Amiga code with GCC

Sun Aug 28, 2016 9:04 pm

jahboater wrote:This gnu inline asm system is used by all three major compilers Intel ICC, LLVM, and of course GCC.
Ok, if you say so. I thought the 4 major C compilers were EasyC, Norcroft C (A.K.A Acorn C), LCC, and GCC.

Though it is inmaterial anyway, it is better practice to write the assembly seperately, assemble with a decent assembler, and call the 'function' written in assembly when neede. That is if you integrate C and assembly.
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

User avatar
Paeryn
Posts: 2805
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Compiling Amiga code with GCC

Sun Aug 28, 2016 10:45 pm

DavidS wrote:Though it is inmaterial anyway, it is better practice to write the assembly seperately, assemble with a decent assembler, and call the 'function' written in assembly when neede. That is if you integrate C and assembly.
If it's a sizable assembler function then yes, but if it's just a few instructions (especially if they are in a tight loop that will be run many times) then you might not want the overhead of a function call.

Gcc uses gas as it's assembler, the exact same assembler that ultimately compiles the assembly version of the C code. It's definately a decent assembler.
She who travels light — forgot something.

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Compiling Amiga code with GCC

Mon Aug 29, 2016 2:19 am

Paeryn wrote:
DavidS wrote:Though it is inmaterial anyway, it is better practice to write the assembly seperately, assemble with a decent assembler, and call the 'function' written in assembly when neede. That is if you integrate C and assembly.
If it's a sizable assembler function then yes, but if it's just a few instructions (especially if they are in a tight loop that will be run many times) then you might not want the overhead of a function call.

Gcc uses gas as it's assembler, the exact same assembler that ultimately compiles the assembly version of the C code. It's definately a decent assembler.
Yea gas is a decent assembler. I primarly use asasm (aka !AS), !ASM, and the integrated BBC BASIC V assembler, as these use a syntax that is more traditionaly ARM + RISC OS (as the two have the same origin, the standards for the CPU assembly should be that of the OS developed with the CPU).

The asasm assembler is nearly perfectly compatible with !OBJAsm, which is the assembler that comes with the DDE and Norcroft C, and has for a long time now.

Unfortunately at this time the only assemblers that do a good job of supporting the newer CPU's are gas, !OBJAsm (commercial), !ExtASM, and the BBC BASIC V Integrated Assembler.

Though I think things are viewed in reverse here. When I use C, it is a few small routines linked into a primarily ARM assembly program.

So I would say that our views are quite different on this.
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

jahboater
Posts: 5027
Joined: Wed Feb 04, 2015 6:38 pm

Re: Compiling Amiga code with GCC

Mon Aug 29, 2016 9:30 am

Paeryn wrote:If it's a sizable assembler function then yes, but if it's just a few instructions (especially if they are in a tight loop that will be run many times) then you might not want the overhead of a function call.
I tend to do something like this (pointless example):

Code: Select all

#ifdef __GNUC__
#define pure    __attribute__ ((pure))
#define inline  __inline__ __attribute__ ((always_inline))
#else
#define pure /**/
#endif

static inline pure int
increment( int n )
{
#if defined(__x86_64__)
  asm( "inc %0" : "+r" (n) );
#elif defined(__aarch64__)
  asm( "add %0,%0,1" : "+r" (n) );
#elif defined(__arm__)
  asm( "add %0,%0,#1" : "+r" (n) );
#else
  ++n;
#endif
  return n;
}
That way its still reasonably portable, its in a function, and gcc will happily optimise it down to the single instruction inline with the rest of the code, or even since its pure, eliminate it.

Return to “C/C++”