IAR embedded workbench "__instrinsic" keyword advice

Started by September 2, 2006
Hi,

I am attempting to figure out how to avoid the use of __intrinsic in my
C code. This is because our test and verification department has an
issue of using code that isn't ANSI C89 compliant. There are constructs
such as the following:

__irq __arm void irq_handler(void)
{
   switch((0xff & IRQIVEC)-1)
  {
   case CIM_COMP1  : COMP1_irq_handler(); break;

  }
}

These aren't actually the regular C functions and are translated by the
C compiler into inline assembler (based upon "intrinsic" definitions
particular to the IAR compiler, i think in the header is "prototyped"
sort of like "__intrinsic __irq__arm(void);" another one is
"__intrinsic __no_operation(void)" ). Our test guy says I should be
looking at instead making a C callable function assembler routine which
would be the equivalent; the reason being is that we can use test
procedures which are standard (C89) and not have platform/compiler
dependent code. I've always worked in C or assembler, and I've never
had to try to combine them. And add to this the utilization of the
intrinsic keyword and I'm just flat confused. Has anyone encountered
this problem (and hopefully fixed it) ?

I know the __intrinsic keyword is used to trigger the compiler to use
inline assembly as well as being a cue to be able to include the code
into it's optimization, whereas it couldn't with directly instantiated
assembler. Our test team has a real problem with using inline assembly
when it comes to testability; which to me seems counterproductive when
doing an embedded application. And since I am low guy on the totem I
don't have much say in the matter; all I can do is capitulate and find
a fix, or come up with some damn good reasons why it won't work any
other way.

Thanks!
--wulf

wulf.grau@gmail.com wrote:
> Hi,
> I am attempting to figure out how to avoid the use of __intrinsic in my > C code. This is because our test and verification department has an > issue of using code that isn't ANSI C89 compliant.
Then, with all due respect, your test department needs to get a grip on reality. Trying to insist on fully standard-compliant code in an embedded software projekt is like insisting on completely oil-free operation of a mechanic repair shop.
> would be the equivalent; the reason being is that we can use test > procedures which are standard (C89) and not have platform/compiler > dependent code.
That reason is a red herring. Using assembler achieves the direct opposite of platform independence or testability. It would hurt test credibility more than those platform-dependent C constructs ever did. While they're still C, you can at least preprocess them out of sight of the test procedures, or even replace them with a portable test rig (e.g. a toy scheduler to take over the role of all the IRQ sources the tester knows nothing about). Generally, it's advisable to not put the platform-dependent things literally into the source code, but rather to generate them from a macro with a platform-dependent definition: ---module.h: #include "platform.h" DECLARE_IRQ_HANDLER(7,function_name) ---module.c: #include "module.h" DEFINE_IRQ_HANDLER(7,function_name) { /* code here */ } platform.h would #define these macros to suit your compiler's needs. -- Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de) Even if all the snow were burnt, ashes would remain.
wulf.grau@gmail.com wrote:
> I am attempting to figure out how to avoid the use of __intrinsic in my > C code. This is because our test and verification department has an > issue of using code that isn't ANSI C89 compliant.
A laudable goal but it may not be entirely achievable. I/O spaces in particular can be an issue. However, if they've done something like implement memcpy with __intrinisic you'll have to grin and bear it. re-implementing the standard library only makes sense if the vendors implementation is either buggey or missing features. There are constructs
> such as the following: > > __irq __arm void irq_handler(void) > {
Well, that's a construct woth avoiding in any case. I've found interrupt keywords and inline assembly to be far more trouble than they are worth. That doesn't mean you have to do the interrupt entirely in assembly, writing an interrupt shell routine is straightforward and as far as I'm concerned part of the process of understanding any particular micro. Inline assembly combine the worst of C with the worst of assembly. Use one or the other. Again it's straightforward to implement small pieces in asm if need be. You can always use th compiler to output a template to start with if the compiler documentation on the ABI is confusing.
> Our test team has a real problem with using inline assembly > when it comes to testability; which to me seems counterproductive when > doing an embedded application.
If they are attempting to test off the micro I can see their point. At least if it's implemented as a separate function it can be stubbed. Naked inline assembly would be a real nightmare.
> And since I am low guy on the totem I > don't have much say in the matter; all I can do is capitulate and find > a fix, or come up with some damn good reasons why it won't work any > other way.
Most uses are not that hard to avoid and IME not that productive in the first place (now I know I'll get comments on the last). Robert
In article <1157226535.495030.154840@m73g2000cwd.googlegroups.com>, 
wulf.grau@gmail.com says...
> Hi, > > I am attempting to figure out how to avoid the use of __intrinsic in my > C code. This is because our test and verification department has an > issue of using code that isn't ANSI C89 compliant. There are constructs > such as the following: > > __irq __arm void irq_handler(void) > { > switch((0xff & IRQIVEC)-1) > { > case CIM_COMP1 : COMP1_irq_handler(); break; > > } > } > > These aren't actually the regular C functions and are translated by the > C compiler into inline assembler (based upon "intrinsic" definitions > particular to the IAR compiler, i think in the header is "prototyped" > sort of like "__intrinsic __irq__arm(void);" another one is > "__intrinsic __no_operation(void)" ). Our test guy says I should be > looking at instead making a C callable function assembler routine which > would be the equivalent; the reason being is that we can use test > procedures which are standard (C89) and not have platform/compiler > dependent code. I've always worked in C or assembler, and I've never > had to try to combine them. And add to this the utilization of the > intrinsic keyword and I'm just flat confused. Has anyone encountered > this problem (and hopefully fixed it) ? > > I know the __intrinsic keyword is used to trigger the compiler to use > inline assembly as well as being a cue to be able to include the code > into it's optimization, whereas it couldn't with directly instantiated > assembler. Our test team has a real problem with using inline assembly > when it comes to testability; which to me seems counterproductive when > doing an embedded application. And since I am low guy on the totem I > don't have much say in the matter; all I can do is capitulate and find > a fix, or come up with some damn good reasons why it won't work any > other way. > > Thanks! > --wulf
This is what happens when a former/failed programmer stops paying attention to reality and starts building castles in the air. Is the purpose of your product to perform a practical function, or to pass an abstract test procedure? How is this rocket scientist in the test department planning to resolve the contradiction of platform independent code and inline assembly? With luck, your manager was once a programmer, has a basic understanding of the issue, and can politely tell the test department to pound sand. In the absence of such a sane response, I would take the assembly generated by the use of the intrinsic function, embed it in a macro, and wrap it around your IRQ handler. As to optimization, if this is an IRQ handler, you probably should not be executing so much code there that an optimizer could help. If you must dance to the test monkey's tune, IAR does provide a pretty good overview of the steps involved to create a C-callable routine. Search the docs for "Calling assembler routines from C", although the result will be no better, and certainly harder to maintain, than the result of using the intrinsic operators. If the Test Monkey will listen to reason (though from your description, this is doubtful), ask him which maintenance situation he would rather deal with: 1. Some time in the future IAR changes their function calling convention. IAR, being a fairly diligent toolmaker, has already updated and tested their intrinsic functions, and hopefully documented the new calling convention. Regardless of their efforts, your original hand- crafted workaround blows up when the code is recompiled, because it makes a set of assumptions about function calls that are no longer valid. You (or your sucessor) must now re-write the code to match the new calling convention, so that a test suite (for which the test department lost the original source 3 years before in a hard drive crash) will execute without a warning. 2. Some time in the future IAR changes their function calling convention. Your code, written with the IAR-supplied intrinsic functions, recompiles and executes without error. The test suite generates a warning, for which you have already placed an explanation in the original source. --Gene
wulf.grau@gmail.com wrote:
> Hi, > > I am attempting to figure out how to avoid the use of __intrinsic in my > C code. This is because our test and verification department has an > issue of using code that isn't ANSI C89 compliant. There are constructs > such as the following: > > __irq __arm void irq_handler(void) > { > switch((0xff & IRQIVEC)-1) > { > case CIM_COMP1 : COMP1_irq_handler(); break; > > } > } > > These aren't actually the regular C functions and are translated by the > C compiler into inline assembler (based upon "intrinsic" definitions > particular to the IAR compiler, i think in the header is "prototyped" > sort of like "__intrinsic __irq__arm(void);" another one is > "__intrinsic __no_operation(void)" ). Our test guy says I should be > looking at instead making a C callable function assembler routine which > would be the equivalent; the reason being is that we can use test > procedures which are standard (C89) and not have platform/compiler > dependent code. I've always worked in C or assembler, and I've never > had to try to combine them. And add to this the utilization of the > intrinsic keyword and I'm just flat confused. Has anyone encountered > this problem (and hopefully fixed it) ? > > I know the __intrinsic keyword is used to trigger the compiler to use > inline assembly as well as being a cue to be able to include the code > into it's optimization, whereas it couldn't with directly instantiated > assembler. Our test team has a real problem with using inline assembly > when it comes to testability; which to me seems counterproductive when > doing an embedded application. And since I am low guy on the totem I > don't have much say in the matter; all I can do is capitulate and find > a fix, or come up with some damn good reasons why it won't work any > other way. > > Thanks! > --wulf >
A function known to the compiler may be "intrinsic" if the function call overhead is too great compared to the function itself. If an "intrinsic" function is called directly, the compiler may choose to emit the code of the "intrinsic" function inline. IAR uses the __intrinsic keyword to mark intrinsic functions. This is a service to you; at least you know what is inlined. The problem with testing intrinsic functions is that they simply might not exist in the source (or object) code form. However, they should be tested no more extensively than any other compiler stuff (e.g., normal library functions. This may confuse the code analysis tools used be your testers. The best way around is to cheat; code analyzers are designed to be cheated on: #ifdef MY_STATIC_ANALYSIS_TOOL #define __intrinsic extern /*for C99, inline is a better choice than extern*/ #define __irq /*nothing*/ /*etc.*/ #endif You may also need to lie that an intrinsic function is implemented elsewhere (e.g. in assembly). The second line of defense, and a good practice overall, is not to use *ANYTHING* directly. Instead, use wrappers (functions or macros) so they can be easily replaced in one place depending on the build type. HTH - Ark
In article <1157226535.495030.154840@m73g2000cwd.googlegroups.com>, 
wulf.grau@gmail.com writes
 >Hi,
 >
 >I am attempting to figure out how to avoid the use of __intrinsic in my
 >C code. This is because our test and verification department has an
 >issue of using code that isn't ANSI C89 compliant.

Why are you an obsolete Us standard,   C89,  when it was superseded by 
the International C90?  Also C90 A1 and 2 TC's  (let alone C99)  The 
compiler you are using will probably be at C95/6  (and in some areas 
C99) compliant.

The other point is that for most embedded systems not using and OS 
(which is most of them)  you can't write pure ISO C anyway You have to 
talk to the HW and use architecture specific stuff.

> "__intrinsic __no_operation(void)" ). Our test guy says I should be > looking at instead making a C callable function assembler routine which > would be the equivalent; the reason being is that we can use test > procedures which are standard (C89) and not have platform/compiler > dependent code.
That is sensible. I usually recommend that the assembler be encapsulated in a C function that only contains the assembler. Usually in a separate file. This helps separate out the machine specific stuff.
>I've always worked in C or assembler, and I've never > had to try to combine them. And add to this the utilization of the > intrinsic keyword and I'm just flat confused. Has anyone encountered > this problem (and hopefully fixed it) ?
Yes. Where possible separate the machine specific and assembler to separate functions in a separate file. -- \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ \/\/\/\/\ Chris Hills Staffs England /\/\/\/\/ /\/\/ chris@phaedsys.org www.phaedsys.org \/\/\ \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/