Message ID | AM4PR07MB157116B6325547B97D4C148CE4400@AM4PR07MB1571.eurprd07.prod.outlook.com |
---|---|
State | New |
Headers | show |
Ping... see https://gcc.gnu.org/ml/gcc-patches/2016-05/msg02010.html Thanks Bernd. On 05/25/16 14:58, Bernd Edlinger wrote: > Hi! > > This restricts the X constraint in asm statements, which > can be easily folded by combine in something completely > invalid. > > It is necessary to allow scratch here, because on i386 > the md_asm_adjust hook inserts them. > > The second test case fails because lra does not > allow all register for anything_ok operands (aka X) > and later it fails to match the two X constraints > in case '0': if (curr_alt[m] == NO_REGS) break. > > There is also an identical bug in the reload pass, > but I do not know how to fix that, as it is almost > used nowhere today. > > > Boot-strapped and regression-tested on x86_64-pc-linux-gnu. > OK for trunk? > > > Thanks > Bernd. >
On 06/06/2016 09:32 AM, Bernd Edlinger wrote: > Ping... > > see https://gcc.gnu.org/ml/gcc-patches/2016-05/msg02010.html > > Thank you for working on the PR and sorry for the delay with LRA part of review. Change in lra-constraints.c is ok for me with the following change. Instead of just - curr_alt[nop] = NO_REGS; + curr_alt[nop] = ALL_REGS; CLEAR_HARD_REG_SET (curr_alt_set[nop]); I'd like to see - curr_alt[nop] = NO_REGS; + curr_alt[nop] = ALL_REGS; - CLEAR_HARD_REG_SET (curr_alt_set[nop]); + COPY_HARD_REG_SET (curr_alt_set[nop], reg_class_contents[ALL_REGS]); Also I don't see /* { dg-do compile } */ in the tests (I don't know what dejagnu does when there is no any dejagnu actions in the test). But with the addition '/* { dg-do compile } */' the test pr59155-2.c is ok for me too. As for recog.c, I can not approve this as I am not a maintainer of it. I only can say that the code looks questionable to me.
On 06/06/2016 11:04 AM, Vladimir Makarov wrote: > On 06/06/2016 09:32 AM, Bernd Edlinger wrote: >> Ping... >> >> see https://gcc.gnu.org/ml/gcc-patches/2016-05/msg02010.html >> >> > Thank you for working on the PR and sorry for the delay with LRA part of > review. > > Change in lra-constraints.c is ok for me with the following change. > Instead of just > > - curr_alt[nop] = NO_REGS; > + curr_alt[nop] = ALL_REGS; > CLEAR_HARD_REG_SET (curr_alt_set[nop]); > > I'd like to see > > - curr_alt[nop] = NO_REGS; > + curr_alt[nop] = ALL_REGS; > - CLEAR_HARD_REG_SET (curr_alt_set[nop]); > + COPY_HARD_REG_SET (curr_alt_set[nop], > reg_class_contents[ALL_REGS]); > > Also I don't see /* { dg-do compile } */ in the tests (I don't know what > dejagnu does when there is no any dejagnu actions in the test). > But with the addition '/* { dg-do compile } */' the test pr59155-2.c is > ok for me too. > > As for recog.c, I can not approve this as I am not a maintainer of it. > I only can say that the code looks questionable to me. I think the question on the recog part is a matter of how we choose to interpret what the "X" constraint means. Does it literally mean accept anything, or accept some subset expressions? I tend to think the former, which means that things like reg_overlap_mentioned_p or its callers have to be bullet-proofed. jeff
On Mon, Jun 06, 2016 at 11:54:04AM -0600, Jeff Law wrote: > >As for recog.c, I can not approve this as I am not a maintainer of it. > >I only can say that the code looks questionable to me. > I think the question on the recog part is a matter of how we choose to > interpret what the "X" constraint means. > > Does it literally mean accept anything, or accept some subset expressions? > > I tend to think the former, which means that things like > reg_overlap_mentioned_p or its callers have to be bullet-proofed. I think it is a bad idea to accept really anything, even for debug insns, which initially accepted arbitrarily large RTL expressions (and still accept stuff like subregs otherwise considered invalid etc.) we found it is highly undesirable, as it is not very good idea for the compile time complexity etc., so now we are trying to limit the complexity of the expressions there by splitting up more complex expressions into smaller ones using temporaries. So, even accept anything should always be accept anything reasonable, because most of the RTL passes don't really expect arbitrarily deep expressions, or expressions where the same reg can appear thousands of times etc. Jakub
On 06/06/2016 12:01 PM, Jakub Jelinek wrote: > On Mon, Jun 06, 2016 at 11:54:04AM -0600, Jeff Law wrote: >>> As for recog.c, I can not approve this as I am not a maintainer of it. >>> I only can say that the code looks questionable to me. >> I think the question on the recog part is a matter of how we choose to >> interpret what the "X" constraint means. >> >> Does it literally mean accept anything, or accept some subset expressions? >> >> I tend to think the former, which means that things like >> reg_overlap_mentioned_p or its callers have to be bullet-proofed. > > I think it is a bad idea to accept really anything, even for debug insns, > which initially accepted arbitrarily large RTL expressions (and still accept > stuff like subregs otherwise considered invalid etc.) we found it is highly > undesirable, as it is not very good idea for the compile time complexity > etc., so now we are trying to limit the complexity of the expressions there > by splitting up more complex expressions into smaller ones using temporaries. > So, even accept anything should always be accept anything reasonable, > because most of the RTL passes don't really expect arbitrarily deep > expressions, or expressions where the same reg can appear thousands of times > etc. The problem is how do you define this subset of expressions you're going to accept and those which you are going to reject. I first pondered accepting RTL leaf nodes (reg, subreg, constants) and rejecting everything else. But I couldn't convince myself that some port might reasonably expect (plus (x) (y)) to match the "X" constraint. jeff
On Mon, Jun 06, 2016 at 12:04:04PM -0600, Jeff Law wrote: > On 06/06/2016 12:01 PM, Jakub Jelinek wrote: > >On Mon, Jun 06, 2016 at 11:54:04AM -0600, Jeff Law wrote: > >>>As for recog.c, I can not approve this as I am not a maintainer of it. > >>>I only can say that the code looks questionable to me. > >>I think the question on the recog part is a matter of how we choose to > >>interpret what the "X" constraint means. > >> > >>Does it literally mean accept anything, or accept some subset expressions? > >> > >>I tend to think the former, which means that things like > >>reg_overlap_mentioned_p or its callers have to be bullet-proofed. > > > >I think it is a bad idea to accept really anything, even for debug insns, > >which initially accepted arbitrarily large RTL expressions (and still accept > >stuff like subregs otherwise considered invalid etc.) we found it is highly > >undesirable, as it is not very good idea for the compile time complexity > >etc., so now we are trying to limit the complexity of the expressions there > >by splitting up more complex expressions into smaller ones using temporaries. > >So, even accept anything should always be accept anything reasonable, > >because most of the RTL passes don't really expect arbitrarily deep > >expressions, or expressions where the same reg can appear thousands of times > >etc. > The problem is how do you define this subset of expressions you're going to > accept and those which you are going to reject. > > I first pondered accepting RTL leaf nodes (reg, subreg, constants) and > rejecting everything else. But I couldn't convince myself that some port > might reasonably expect (plus (x) (y)) to match the "X" constraint. It is always going to be arbitrary. Perhaps RTL leaf nodes (if including MEM, then perhaps with valid address only), and unary/binary/ternary RTL expressions with RTL leaf node operands? Or union of what is accepted by any other constraint? Or "g" plus any constants? Jakub
On Mon, 6 Jun 2016, Jakub Jelinek wrote: > On Mon, Jun 06, 2016 at 12:04:04PM -0600, Jeff Law wrote: >> On 06/06/2016 12:01 PM, Jakub Jelinek wrote: >>> On Mon, Jun 06, 2016 at 11:54:04AM -0600, Jeff Law wrote: >>>>> As for recog.c, I can not approve this as I am not a maintainer of it. >>>>> I only can say that the code looks questionable to me. >>>> I think the question on the recog part is a matter of how we choose to >>>> interpret what the "X" constraint means. >>>> >>>> Does it literally mean accept anything, or accept some subset expressions? >>>> >>>> I tend to think the former, which means that things like >>>> reg_overlap_mentioned_p or its callers have to be bullet-proofed. >>> >>> I think it is a bad idea to accept really anything, even for debug insns, >>> which initially accepted arbitrarily large RTL expressions (and still accept >>> stuff like subregs otherwise considered invalid etc.) we found it is highly >>> undesirable, as it is not very good idea for the compile time complexity >>> etc., so now we are trying to limit the complexity of the expressions there >>> by splitting up more complex expressions into smaller ones using temporaries. >>> So, even accept anything should always be accept anything reasonable, >>> because most of the RTL passes don't really expect arbitrarily deep >>> expressions, or expressions where the same reg can appear thousands of times >>> etc. >> The problem is how do you define this subset of expressions you're going to >> accept and those which you are going to reject. >> >> I first pondered accepting RTL leaf nodes (reg, subreg, constants) and >> rejecting everything else. But I couldn't convince myself that some port >> might reasonably expect (plus (x) (y)) to match the "X" constraint. > > It is always going to be arbitrary. > Perhaps RTL leaf nodes (if including MEM, then perhaps with valid address > only), and unary/binary/ternary RTL expressions with RTL leaf node operands? > Or union of what is accepted by any other constraint? > Or "g" plus any constants? The last one would miss floating point registers (no 2 platforms use the same letter for those, hence my quest for something more generic). The goal of the experiment is described in PR59159 (for which "+X" is unlikely to be the right answer, in particular because it is meaningless for constants). I don't know in what context people use the "X" constraint, or even better "=X"...
On Mon, Jun 06, 2016 at 09:27:56PM +0200, Marc Glisse wrote: > The last one would miss floating point registers (no 2 platforms use the > same letter for those, hence my quest for something more generic). > > The goal of the experiment is described in PR59159 (for which "+X" is > unlikely to be the right answer, in particular because it is meaningless for > constants). I don't know in what context people use the "X" constraint, or > even better "=X"... X constraint has been added mainly for uses in match_scratch like: (clobber (match_scratch:SI 2 "=X,X,X,&r")) or when the predicate takes care of everything and it is not needed to specify anything further: [(set (match_operand:SWI12 0 "push_operand" "=X") (match_operand:SWI12 1 "nonmemory_no_elim_operand" "rn"))] Using it in inline asm generally has resulted in lots of issues, including ICEs etc., so nothing I'd recommend to use. Jakub
On 06/06/16 20:08, Jakub Jelinek wrote: > On Mon, Jun 06, 2016 at 12:04:04PM -0600, Jeff Law wrote: >> On 06/06/2016 12:01 PM, Jakub Jelinek wrote: >>> On Mon, Jun 06, 2016 at 11:54:04AM -0600, Jeff Law wrote: >>>>> As for recog.c, I can not approve this as I am not a maintainer of it. >>>>> I only can say that the code looks questionable to me. >>>> I think the question on the recog part is a matter of how we choose to >>>> interpret what the "X" constraint means. >>>> >>>> Does it literally mean accept anything, or accept some subset expressions? >>>> >>>> I tend to think the former, which means that things like >>>> reg_overlap_mentioned_p or its callers have to be bullet-proofed. AFACT this is not the only place where overly complex RTL trees can cause an ICE. >>> >>> I think it is a bad idea to accept really anything, even for debug insns, >>> which initially accepted arbitrarily large RTL expressions (and still accept >>> stuff like subregs otherwise considered invalid etc.) we found it is highly >>> undesirable, as it is not very good idea for the compile time complexity >>> etc., so now we are trying to limit the complexity of the expressions there >>> by splitting up more complex expressions into smaller ones using temporaries. >>> So, even accept anything should always be accept anything reasonable, >>> because most of the RTL passes don't really expect arbitrarily deep >>> expressions, or expressions where the same reg can appear thousands of times >>> etc. >> The problem is how do you define this subset of expressions you're going to >> accept and those which you are going to reject. >> >> I first pondered accepting RTL leaf nodes (reg, subreg, constants) and >> rejecting everything else. But I couldn't convince myself that some port >> might reasonably expect (plus (x) (y)) to match the "X" constraint. > > It is always going to be arbitrary. > Perhaps RTL leaf nodes (if including MEM, then perhaps with valid address > only), and unary/binary/ternary RTL expressions with RTL leaf node operands? > Or union of what is accepted by any other constraint? > Or "g" plus any constants? Yes. That is what I think too, "X" is probably not used often in practice, but if it is allowed, it should at least not result in an ICE. "X" should allow to feed "whatsoever" valid C expressions to the asm input, and using the %-expression in the assembler string should not cause an ICE. And "X" really means different "whatsoever" things in asm statements and in .md files, even md.texi has different text for internally used "X" constraint and assembler "X" constraint, so that should be OK. According to md.texi "g" should already mean: @item @samp{g} Any register, memory or immediate integer operand is allowed, except for registers that are not general registers. Which is the same as general_operand(op, VOIDmode). And in other words, that should be everything that is in "r", "m" and "i" constraints. However if I compare commond.md ... (define_constraint "i" "Matches a general integer constant." (and (match_test "CONSTANT_P (op)") (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)"))) ... against recog.c, general_operand seems to allow less i.e. checks targetm.legitimate_constant_p additionally. So that is something I don't really understand, I mean if a constant is not a "legitimate" constant by the target's definition, why should it be safe to use in later in targetm.asm_out.print_operand? Bernd.
On 06/07/2016 11:58 AM, Bernd Edlinger wrote: > > AFACT this is not the only place where overly complex RTL trees can > cause an ICE. That wouldn't surprise me at all -- but the design of RTL is such that it can be arbitrarily complex. Essentially, routines can not make assumptions about the complexity of the RTL they're given -- except for any guards/pre-conditions set up in the caller. > > Yes. That is what I think too, "X" is probably not used often in > practice, but if it is allowed, it should at least not result in an ICE. There's no disagreement about "X" should never result in an ICE. The question is whether or not "X" truly means an arbitrary piece of RTL or some tighter subset of RTL. I guess one could also raise the question of whether or not "X" should ever be exposed to asms. "X"'s original intent IIRC was to specify that for a particular alternative the operand didn't matter and would never be used. This comes up with scratch registers for example. > > "X" should allow to feed "whatsoever" valid C expressions to the asm > input, and using the %-expression in the assembler string should not > cause an ICE. Actually it doesn't even have to be a valid C expression. It might have started as a C expression from an ASM statement, but been modified by various RTL optimization passes into something that isn't necessarily a valid C expression. > However if I compare commond.md ... > > (define_constraint "i" > "Matches a general integer constant." > (and (match_test "CONSTANT_P (op)") > (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)"))) > > ... against recog.c, general_operand seems to allow less i.e. checks > targetm.legitimate_constant_p additionally. So that is something > I don't really understand, I mean if a constant is not a "legitimate" > constant by the target's definition, why should it be safe to use > in later in targetm.asm_out.print_operand? Legitimacy in this context is usually something related to operands that have to be reloaded for PIC code generation. They may print just fine, but from a code generation standpoint they require special handling. One could argue that this is inconsistent and it ought to be cleaned up, but that's separate from the "X" issue. jeff
On 06/06/2016 01:40 PM, Jakub Jelinek wrote: > On Mon, Jun 06, 2016 at 09:27:56PM +0200, Marc Glisse wrote: >> The last one would miss floating point registers (no 2 platforms use the >> same letter for those, hence my quest for something more generic). >> >> The goal of the experiment is described in PR59159 (for which "+X" is >> unlikely to be the right answer, in particular because it is meaningless for >> constants). I don't know in what context people use the "X" constraint, or >> even better "=X"... > > X constraint has been added mainly for uses in match_scratch like: > (clobber (match_scratch:SI 2 "=X,X,X,&r")) > or when the predicate takes care of everything and it is not needed to > specify anything further: > [(set (match_operand:SWI12 0 "push_operand" "=X") > (match_operand:SWI12 1 "nonmemory_no_elim_operand" "rn"))] > Using it in inline asm generally has resulted in lots of issues, including > ICEs etc., so nothing I'd recommend to use. So would it make sense to define it as not available for use in ASMs? I realize that's potentially a user-visible change, but it might be a reasonable one to make. jeff
On Thu, Jun 09, 2016 at 10:30:13AM -0600, Jeff Law wrote: > On 06/06/2016 01:40 PM, Jakub Jelinek wrote: > >On Mon, Jun 06, 2016 at 09:27:56PM +0200, Marc Glisse wrote: > >>The last one would miss floating point registers (no 2 platforms use the > >>same letter for those, hence my quest for something more generic). > >> > >>The goal of the experiment is described in PR59159 (for which "+X" is > >>unlikely to be the right answer, in particular because it is meaningless for > >>constants). I don't know in what context people use the "X" constraint, or > >>even better "=X"... > > > >X constraint has been added mainly for uses in match_scratch like: > >(clobber (match_scratch:SI 2 "=X,X,X,&r")) > >or when the predicate takes care of everything and it is not needed to > >specify anything further: > > [(set (match_operand:SWI12 0 "push_operand" "=X") > > (match_operand:SWI12 1 "nonmemory_no_elim_operand" "rn"))] > >Using it in inline asm generally has resulted in lots of issues, including > >ICEs etc., so nothing I'd recommend to use. > So would it make sense to define it as not available for use in ASMs? I > realize that's potentially a user-visible change, but it might be a > reasonable one to make. Yes, I'm all in favor in disabling X constraint for inline asm. Especially if people actually try to print it as well, rather than make it unused. That is a sure path to ICEs. Jakub
On Thu, Jun 09, 2016 at 06:43:04PM +0200, Jakub Jelinek wrote: > Yes, I'm all in favor in disabling X constraint for inline asm. > Especially if people actually try to print it as well, rather than make it > unused. That is a sure path to ICEs. Though, on the other side, even our documentation mentions asm volatile ("mtfsf 255,%1" : "=X"(sum): "f"(fpenv)); So perhaps we need to error just in case such an argument is printed? Jakub
On 06/09/16 18:45, Jakub Jelinek wrote: > On Thu, Jun 09, 2016 at 06:43:04PM +0200, Jakub Jelinek wrote: >> Yes, I'm all in favor in disabling X constraint for inline asm. >> Especially if people actually try to print it as well, rather than make it >> unused. That is a sure path to ICEs. > > Though, on the other side, even our documentation mentions > asm volatile ("mtfsf 255,%1" : "=X"(sum): "f"(fpenv)); > So perhaps we need to error just in case such an argument is printed? note that "=X" is also introduced internally in this asm statement: asm ("cmpl %2, 0" : "=@ccz"(z), "=@ccb"(b): "r"(i)); see i386.c, ix86_md_asm_adjust. The first =@cc is replaced by "=Bf" constraint but any further =@cc are replaced by "=X" and scratch operand. Printing the "=X" scratch is harmless, but printing the "=Bf" causes another ICE, I shall submit a follow up patch for that: asm ("# %0" : "=@ccz"(z)); test.c:6:1: internal compiler error: in print_reg, at config/i386/i386.c:17193 } ^ 0xedfc30 print_reg(rtx_def*, int, _IO_FILE*) ../../gcc-trunk/gcc/config/i386/i386.c:17189 0xf048a4 ix86_print_operand(_IO_FILE*, rtx_def*, int) ../../gcc-trunk/gcc/config/i386/i386.c:17867 0x8bf87c output_operand(rtx_def*, int) ../../gcc-trunk/gcc/final.c:3847 0x8c00ee output_asm_insn(char const*, rtx_def**) ../../gcc-trunk/gcc/final.c:3763 0x8c1f9c final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*) ../../gcc-trunk/gcc/final.c:2628 0x8c25c9 final(rtx_insn*, _IO_FILE*, int) ../../gcc-trunk/gcc/final.c:2045 0x8c2da9 rest_of_handle_final ../../gcc-trunk/gcc/final.c:4445 0x8c2da9 execute ../../gcc-trunk/gcc/final.c:4520 Well, regarding the X constraint, I do think that it's definitely OK to use different rules if it is used in asms vs. when if it is used internally in .md files. The patch handles X in asms to be just a synonym to the g constraint, except that g allows only GENERAL_REGS and X allows ALL_REGS. What I am not sure of, is if X should allow more than g in terms of CONSTANT_P. I think it should not, because probably the CONSTANT_P handling in general_operand is likely smarter than that of the i constraint. Bernd.
On 06/09/2016 10:45 AM, Jakub Jelinek wrote: > On Thu, Jun 09, 2016 at 06:43:04PM +0200, Jakub Jelinek wrote: >> Yes, I'm all in favor in disabling X constraint for inline asm. >> Especially if people actually try to print it as well, rather than make it >> unused. That is a sure path to ICEs. > > Though, on the other side, even our documentation mentions > asm volatile ("mtfsf 255,%1" : "=X"(sum): "f"(fpenv)); > So perhaps we need to error just in case such an argument is printed? Are you thinking to scan the output string for %<N> for the appropriate <N>? That shouldn't be too hard. But that's not sufficient to address the problem Bernd is trying to tackle AFAICT. Jeff
On 06/21/16 00:06, Jeff Law wrote: > On 06/09/2016 10:45 AM, Jakub Jelinek wrote: >> On Thu, Jun 09, 2016 at 06:43:04PM +0200, Jakub Jelinek wrote: >>> Yes, I'm all in favor in disabling X constraint for inline asm. >>> Especially if people actually try to print it as well, rather than >>> make it >>> unused. That is a sure path to ICEs. >> >> Though, on the other side, even our documentation mentions >> asm volatile ("mtfsf 255,%1" : "=X"(sum): "f"(fpenv)); >> So perhaps we need to error just in case such an argument is printed? > Are you thinking to scan the output string for %<N> for the appropriate > <N>? That shouldn't be too hard. But that's not sufficient to address > the problem Bernd is trying to tackle AFAICT. Correct. And furthermore, the use case with matching X input & output that Marc wanted to use, seems to be a valid one. Because "+X" allows more registers than "+g" or "+r", it should create less register pressure. And although it is probably unpredictable if a register of the class "ALL_REGISTERS" will work for an assembler instruction, it is still interesting to print it in an assembler comment. Bernd.
Index: gcc/lra-constraints.c =================================================================== --- gcc/lra-constraints.c (revision 236569) +++ gcc/lra-constraints.c (working copy) @@ -1854,7 +1854,7 @@ process_alt_operands (int only_alternative) if (curr_static_id->operand_alternative[opalt_num].anything_ok) { /* Fast track for no constraints at all. */ - curr_alt[nop] = NO_REGS; + curr_alt[nop] = ALL_REGS; CLEAR_HARD_REG_SET (curr_alt_set[nop]); curr_alt_win[nop] = true; curr_alt_match_win[nop] = false; Index: gcc/recog.c =================================================================== --- gcc/recog.c (revision 236569) +++ gcc/recog.c (working copy) @@ -1757,6 +1757,10 @@ asm_operand_ok (rtx op, const char *constraint, co result = 1; break; + case 'X': + if (scratch_operand (op, VOIDmode)) + result = 1; + /* ... fall through ... */ case 'g': if (general_operand (op, VOIDmode)) result = 1; Index: gcc/testsuite/gcc.dg/torture/pr59155-1.c =================================================================== --- gcc/testsuite/gcc.dg/torture/pr59155-1.c (revision 0) +++ gcc/testsuite/gcc.dg/torture/pr59155-1.c (working copy) @@ -0,0 +1,7 @@ +double f(double x){ + asm volatile("":"+X"(x)); + return x; +} +double g(double x,double y){ + return f(f(x)+f(y)); +} Index: gcc/testsuite/gcc.dg/torture/pr59155-2.c =================================================================== --- gcc/testsuite/gcc.dg/torture/pr59155-2.c (revision 0) +++ gcc/testsuite/gcc.dg/torture/pr59155-2.c (working copy) @@ -0,0 +1,7 @@ +double f(double x){ + asm volatile("":"+X"(x)); + return x; +} +double g(){ + return f(1.); +} Index: gcc/testsuite/gcc.dg/torture/pr59155-3.c =================================================================== --- gcc/testsuite/gcc.dg/torture/pr59155-3.c (revision 0) +++ gcc/testsuite/gcc.dg/torture/pr59155-3.c (working copy) @@ -0,0 +1,27 @@ +void +noprop1 (int **x, int y, int z) +{ + int *ptr = *x + y * z / 11; + asm volatile ("noprop1 %0" : : "X" (*ptr)); +} + +void +noprop2 (int **x, int y, int z) +{ + int *ptr = *x + y * z / 11; + asm volatile ("noprop2 %0" : : "X" (ptr)); +} + +int *global_var; + +void +const1 (void) +{ + asm volatile ("const1 %0" : : "X" (global_var)); +} + +void +const2 (void) +{ + asm volatile ("const2 %0" : : "X" (*global_var)); +}