1 #include "d-gcc-includes.h"
27 AsmArg(AsmArgType type
, Expression
* expr
, AsmArgMode mode
) {
36 unsigned insnTemplateLen
;
37 Array args
; // of AsmArg
51 /* Apple GCC extends ASM_EXPR to five operands; cannot use build4. */
53 d_build_asm_stmt(tree t1
, tree t2
, tree t3
, tree t4
)
55 tree t
= make_node(ASM_EXPR
);
56 TREE_TYPE(t
) = void_type_node
;
57 SET_EXPR_LOCATION(t
, input_location
);
58 TREE_OPERAND(t
,0) = t1
;
59 TREE_OPERAND(t
,1) = t2
;
60 TREE_OPERAND(t
,2) = t3
;
61 TREE_OPERAND(t
,3) = t4
;
62 TREE_SIDE_EFFECTS(t
) = 1;
67 AsmStatement::AsmStatement(Loc loc
, Token
*tokens
) :
70 this->tokens
= tokens
; // Do I need to copy these?
78 Statement
*AsmStatement::syntaxCopy()
80 // copy tokens? copy 'code'?
81 AsmStatement
* a_s
= new AsmStatement(loc
,tokens
);
82 a_s
->asmcode
= asmcode
;
83 a_s
->refparam
= refparam
;
85 a_s
->regs
= a_s
->regs
;
89 void AsmStatement::toCBuffer(OutBuffer
*buf
, HdrGenState
*hgs
)
91 bool sep
= 0, nsep
= 0;
92 buf
->writestring("asm { ");
94 for (Token
* t
= tokens
; t
; t
= t
->next
) {
115 buf
->writestring(t
->toChars());
117 buf
->writestring("; }");
121 int AsmStatement::comeFrom()
129 AsmStatement::blockExit()
131 // TODO: Be smarter about this
137 /* GCC does not support jumps from asm statements. When optimization
138 is turned on, labels referenced only from asm statements will not
139 be output at the correct location. There are ways around this:
141 1) Reference the label with a reachable goto statement
142 2) Have reachable computed goto in the function
143 3) Hack cfgbuild.c to act as though there is a computed goto.
145 These are all pretty bad, but if would be nice to be able to tell
146 GCC not to optimize in this case (even on per label/block basis).
148 The current solution is output our own private labels (as asm
149 statements) along with the "real" label. If the label happens to
150 be referred to by a goto statement, the "real" label will also be
151 output in the correct location.
153 Also had to add 'asmLabelNum' to LabelDsymbol to indicate it needs
156 (junk) d-lang.cc:916:case LABEL_DECL: // C doesn't do this. D needs this for referencing labels in inline assembler since there may be not goto referencing it.
160 static unsigned d_priv_asm_label_serial
= 0;
162 // may need to make this target-specific
163 static void d_format_priv_asm_label(char * buf
, unsigned n
)
165 //ASM_GENERATE_INTERNAL_LABEL(buf, "LDASM", n);//inserts a '*' for use with assemble_name
166 sprintf(buf
, ".LDASM%u", n
);
170 d_expand_priv_asm_label(IRState
* irs
, unsigned n
)
173 d_format_priv_asm_label(buf
, n
);
175 tree insnt
= build_string(strlen(buf
), buf
);
177 expand_asm(insnt
, 1);
179 tree t
= d_build_asm_stmt(insnt
, NULL_TREE
, NULL_TREE
, NULL_TREE
);
180 ASM_VOLATILE_P( t
) = 1;
181 ASM_INPUT_P( t
) = 1; // what is this doing?
186 ExtAsmStatement::ExtAsmStatement(Loc loc
, Expression
*insnTemplate
, Expressions
*args
, Array
*argNames
,
187 Expressions
*argConstraints
, int nOutputArgs
, Expressions
*clobbers
)
190 this->insnTemplate
= insnTemplate
;
192 this->argNames
= argNames
;
193 this->argConstraints
= argConstraints
;
194 this->nOutputArgs
= nOutputArgs
;
195 this->clobbers
= clobbers
;
198 Statement
*ExtAsmStatement::syntaxCopy()
200 /* insnTemplate, argConstraints, and clobbers would be
201 semantically static in GNU C. */
202 Expression
*insnTemplate
= this->insnTemplate
->syntaxCopy();
203 Expressions
* args
= Expression::arraySyntaxCopy(this->args
);
204 // argNames is an array of identifiers
205 Expressions
* argConstraints
= Expression::arraySyntaxCopy(this->argConstraints
);
206 Expressions
* clobbers
= Expression::arraySyntaxCopy(this->clobbers
);
207 return new ExtAsmStatement(loc
, insnTemplate
, args
, argNames
,
208 argConstraints
, nOutputArgs
, clobbers
);
211 Statement
*ExtAsmStatement::semantic(Scope
*sc
)
213 insnTemplate
= insnTemplate
->semantic(sc
);
214 insnTemplate
= insnTemplate
->optimize(WANTvalue
);
215 if (insnTemplate
->op
!= TOKstring
|| ((StringExp
*)insnTemplate
)->sz
!= 1)
216 error("instruction template must be a constant char string");
218 for (unsigned i
= 0; i
< args
->dim
; i
++) {
219 Expression
* e
= (Expression
*) args
->data
[i
];
222 e
= e
->modifiableLvalue(sc
, NULL
);
224 e
= e
->optimize(WANTvalue
|WANTinterpret
);
227 e
= (Expression
*) argConstraints
->data
[i
];
229 e
= e
->optimize(WANTvalue
);
230 if (e
->op
!= TOKstring
|| ((StringExp
*)e
)->sz
!= 1)
231 error("constraint must be a constant char string");
232 argConstraints
->data
[i
] = e
;
235 for (unsigned i
= 0; i
< clobbers
->dim
; i
++) {
236 Expression
* e
= (Expression
*) clobbers
->data
[i
];
238 e
= e
->optimize(WANTvalue
);
239 if (e
->op
!= TOKstring
|| ((StringExp
*)e
)->sz
!= 1)
240 error("clobber specification must be a constant char string");
241 clobbers
->data
[i
] = e
;
249 ExtAsmStatement::blockExit()
251 // TODO: Be smarter about this
257 // StringExp::toIR usually adds a NULL. We don't want that...
260 naturalString(Expression
* e
)
262 // don't fail, just an error?
263 assert(e
->op
== TOKstring
);
264 StringExp
* s
= (StringExp
*) e
;
266 return build_string(s
->len
, (char *) s
->string
);
269 void ExtAsmStatement::toIR(IRState
*irs
)
273 ListMaker tree_clobbers
;
275 gen
.doLineNote( loc
);
278 for (unsigned i
= 0; i
< args
->dim
; i
++)
280 Identifier
* name
= argNames
->data
[i
] ? (Identifier
*) argNames
->data
[i
] : NULL
;
281 Expression
* constr
= (Expression
*) argConstraints
->data
[i
];
282 tree p
= tree_cons(name
? build_string(name
->len
, name
->string
) : NULL_TREE
,
283 naturalString(constr
), NULL_TREE
);
284 tree v
= ((Expression
*) args
->data
[i
])->toElem(irs
);
292 for (unsigned i
= 0; i
< clobbers
->dim
; i
++) {
293 Expression
* clobber
= (Expression
*) clobbers
->data
[i
];
294 tree_clobbers
.cons(NULL_TREE
, naturalString(clobber
));
297 irs
->doAsm(naturalString(insnTemplate
), outputs
.head
, inputs
.head
, tree_clobbers
.head
);
301 #include "d-asm-i386.h"
303 #define D_NO_INLINE_ASM_AT_ALL
306 #ifndef D_NO_INLINE_ASM_AT_ALL
308 bool d_have_inline_asm() { return true; }
310 Statement
*AsmStatement::semantic(Scope
*sc
)
313 sc
->func
->inlineAsm
= 1;
314 sc
->func
->inlineStatus
= ILSno
; // %% not sure
315 // %% need to set DECL_UNINLINABLE too?
316 sc
->func
->hasReturnExp
= 1; // %% DMD does this, apparently...
318 // empty statement -- still do the above things because they might be expected?
322 AsmProcessor
ap(sc
, this);
328 AsmStatement::toIR(IRState
* irs
)
330 gen
.doLineNote( loc
);
335 static tree i_cns
= 0;
336 static tree p_cns
= 0;
337 static tree m_cns
= 0;
338 static tree mw_cns
= 0;
339 static tree mrw_cns
= 0;
340 static tree memory_name
= 0;
343 i_cns
= build_string(1, "i");
344 p_cns
= build_string(1, "p");
345 m_cns
= build_string(1, "m");
346 mw_cns
= build_string(2, "=m");
347 mrw_cns
= build_string(2, "+m");
348 memory_name
= build_string(6, "memory");
354 AsmCode
* code
= (AsmCode
*) asmcode
;
358 //tree dollar_label = NULL_TREE;//OLD
359 HOST_WIDE_INT var_frame_offset
; // "frame_offset" is a macro
360 bool clobbers_mem
= code
->clobbersMemory
;
365 assert(code
->args
.dim
<= 10);
367 for (unsigned i
= 0; i
< code
->args
.dim
; i
++) {
368 AsmArg
* arg
= (AsmArg
*) code
->args
.data
[i
];
370 bool is_input
= true;
371 tree arg_val
= NULL_TREE
;
372 tree cns
= NULL_TREE
;
376 arg_val
= arg
->expr
->toElem(irs
);
381 if (arg
->expr
->op
== TOKvar
)
382 arg_val
= ((VarExp
*) arg
->expr
)->var
->toSymbol()->Stree
;
383 else if (arg
->expr
->op
== TOKdsymbol
) {
384 arg_val
= irs
->getLabelTree( (LabelDsymbol
*) ((DsymbolExp
*) arg
->expr
)->s
);
387 arg_val
= irs
->addressOf(arg_val
);
391 if (arg
->expr
->op
== TOKvar
)
392 arg_val
= ((VarExp
*) arg
->expr
)->var
->toSymbol()->Stree
;
393 else if (arg
->expr
->op
== TOKfloat64
)
395 /* Constant scalar value. In order to reference it as memory,
396 create an anonymous static var. */
397 tree cnst
= build_decl(VAR_DECL
, NULL_TREE
, arg
->expr
->type
->toCtype());
398 g
.ofile
->giveDeclUniqueName(cnst
);
399 DECL_INITIAL(cnst
) = arg
->expr
->toElem(irs
);
400 TREE_STATIC(cnst
) = TREE_CONSTANT(cnst
) = TREE_READONLY(cnst
) =
401 TREE_PRIVATE(cnst
) = DECL_ARTIFICIAL(cnst
) = DECL_IGNORED_P(cnst
) = 1;
402 g
.ofile
->rodc(cnst
, 1);
406 arg_val
= arg
->expr
->toElem(irs
);
407 if (DECL_P( arg_val
))
408 TREE_ADDRESSABLE( arg_val
) = 1;
410 case Mode_Input
: cns
= m_cns
; break;
411 case Mode_Output
: cns
= mw_cns
; is_input
= false; break;
412 case Mode_Update
: cns
= mrw_cns
; is_input
= false; break;
413 default: assert(0); break;
416 case Arg_FrameRelative
:
417 if (arg
->expr
->op
== TOKvar
)
418 arg_val
= ((VarExp
*) arg
->expr
)->var
->toSymbol()->Stree
;
421 if ( getFrameRelativeValue(arg_val
, & var_frame_offset
) ) {
422 arg_val
= irs
->integerConstant(var_frame_offset
);
425 this->error("%s", "argument not frame relative");
428 if (arg
->mode
!= Mode_Input
)
432 var_frame_offset
= cfun
->x_frame_offset
;
433 if (var_frame_offset
< 0)
434 var_frame_offset
= - var_frame_offset
;
435 arg_val
= irs
->integerConstant( var_frame_offset
);
440 dollar_label = build_decl(LABEL_DECL, NULL_TREE, void_type_node);
441 arg_val = dollar_label;
449 arg_map
[i
] = --input_idx
;
450 inputs
.cons(tree_cons(NULL_TREE
, cns
, NULL_TREE
), arg_val
);
452 arg_map
[i
] = n_outputs
++;
453 outputs
.cons(tree_cons(NULL_TREE
, cns
, NULL_TREE
), arg_val
);
457 // Telling GCC that callee-saved registers are clobbered makes it preserve
458 // those registers. This changes the stack from what a naked function
461 if (! irs
->func
->naked
) {
462 for (int i
= 0; i
< 32; i
++) {
463 if (regs
& (1 << i
)) {
464 clobbers
.cons(NULL_TREE
, regInfo
[i
].gccName
);
467 for (int i
= 0; i
< 32; i
++) {
468 if (code
->moreRegs
& (1 << (i
-32))) {
469 clobbers
.cons(NULL_TREE
, regInfo
[i
].gccName
);
473 clobbers
.cons(NULL_TREE
, memory_name
);
477 // Remap argument numbers
478 for (unsigned i
= 0; i
< code
->args
.dim
; i
++) {
480 arg_map
[i
] = -arg_map
[i
] - 1 + n_outputs
;
484 char * p
= code
->insnTemplate
;
485 char * q
= p
+ code
->insnTemplateLen
;
486 //printf("start: %.*s\n", code->insnTemplateLen, code->insnTemplate);
489 if (*p
>= '0' && *p
<= '9') {
490 // %% doesn't check against nargs
491 *p
= '0' + arg_map
[*p
- '0'];
493 } else if (*p
== '%') {
496 //assert(*p == '%');// could be 'a', etc. so forget it..
497 } else if (*p
== '%')
502 //printf("final: %.*s\n", code->insnTemplateLen, code->insnTemplate);
504 tree insnt
= build_string(code
->insnTemplateLen
, code
->insnTemplate
);
506 location_t gcc_loc
= { loc
.filename
, loc
.linnum
};
507 expand_asm_operands(insnt
, outputs
.head
, inputs
.head
, clobbers
.head
, 1, gcc_loc
);
509 tree t
= d_build_asm_stmt(insnt
, outputs
.head
, inputs
.head
, clobbers
.head
);
510 ASM_VOLATILE_P( t
) = 1;
513 //if (dollar_label)//OLD
514 // expand_label(dollar_label);
515 if (code
->dollarLabel
)
516 d_expand_priv_asm_label(irs
, code
->dollarLabel
);
521 bool d_have_inline_asm() { return false; }
524 AsmStatement::semantic(Scope
*sc
)
526 sc
->func
->inlineAsm
= 1;
527 return Statement::semantic(sc
);
531 AsmStatement::toIR(IRState
*)
533 sorry("assembler statements are not supported on this target");