racpugas.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Mazen NEIFER
  4. Does the parsing for the i386 GNU AS styled inline assembler.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. Unit racpugas;
  19. {$i fpcdefs.inc}
  20. Interface
  21. uses
  22. raatt,racpu;
  23. type
  24. tSparcReader = class(tattreader)
  25. function is_asmopcode(const s: string):boolean;override;
  26. procedure handleopcode;override;
  27. procedure BuildReference(oper : tSparcoperand);
  28. procedure BuildOperand(oper : tSparcoperand);
  29. procedure BuildOpCode(instr : tSparcinstruction);
  30. procedure ReadPercent(oper : tSparcoperand);
  31. procedure ReadSym(oper : tSparcoperand);
  32. procedure ConvertCalljmp(instr : tSparcinstruction);
  33. procedure handlepercent;override;
  34. end;
  35. Implementation
  36. uses
  37. { helpers }
  38. cutils,
  39. { global }
  40. globtype,verbose,
  41. systems,
  42. { aasm }
  43. cpubase,aasmbase,aasmtai,aasmcpu,
  44. { symtable }
  45. symconst,symsym,
  46. { parser }
  47. scanner,
  48. procinfo,
  49. rabase,rautils,
  50. cgbase,cgobj
  51. ;
  52. procedure TSparcReader.ReadSym(oper : tSparcoperand);
  53. var
  54. tempstr : string;
  55. typesize,l,k : aint;
  56. begin
  57. tempstr:=actasmpattern;
  58. Consume(AS_ID);
  59. { typecasting? }
  60. if (actasmtoken=AS_LPAREN) and
  61. SearchType(tempstr,typesize) then
  62. begin
  63. oper.hastype:=true;
  64. Consume(AS_LPAREN);
  65. BuildOperand(oper);
  66. Consume(AS_RPAREN);
  67. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  68. oper.SetSize(typesize,true);
  69. end
  70. else
  71. if not oper.SetupVar(tempstr,false) then
  72. Message1(sym_e_unknown_id,tempstr);
  73. { record.field ? }
  74. if actasmtoken=AS_DOT then
  75. begin
  76. BuildRecordOffsetSize(tempstr,l,k);
  77. inc(oper.opr.ref.offset,l);
  78. end;
  79. end;
  80. procedure TSparcReader.ReadPercent(oper : tSparcoperand);
  81. begin
  82. { check for ...@ }
  83. if actasmtoken=AS_AT then
  84. begin
  85. if (oper.opr.ref.symbol=nil) and
  86. (oper.opr.ref.offset = 0) then
  87. Message(asmr_e_invalid_reference_syntax);
  88. Consume(AS_AT);
  89. if actasmtoken=AS_ID then
  90. begin
  91. if upper(actasmpattern)='LO' then
  92. oper.opr.ref.refaddr:=addr_lo
  93. else if upper(actasmpattern)='HI' then
  94. oper.opr.ref.refaddr:=addr_hi
  95. else
  96. Message(asmr_e_invalid_reference_syntax);
  97. Consume(AS_ID);
  98. end
  99. else
  100. Message(asmr_e_invalid_reference_syntax);
  101. end;
  102. end;
  103. Procedure TSparcReader.BuildReference(oper : tSparcoperand);
  104. var
  105. l : aint;
  106. regs : byte;
  107. hasimm : boolean;
  108. begin
  109. oper.initref;
  110. regs:=0;
  111. hasimm:=false;
  112. Consume(AS_LBRACKET);
  113. repeat
  114. Case actasmtoken of
  115. AS_INTNUM,
  116. AS_MINUS,
  117. AS_PLUS:
  118. Begin
  119. if hasimm or (regs>1) then
  120. Begin
  121. Message(asmr_e_invalid_reference_syntax);
  122. RecoverConsume(true);
  123. break;
  124. End;
  125. oper.opr.Ref.Offset:=BuildConstExpression(false,true);
  126. hasimm:=true;
  127. End;
  128. AS_REGISTER:
  129. Begin
  130. if regs<2 then
  131. begin
  132. if regs=0 then
  133. oper.opr.ref.base:=actasmregister
  134. else
  135. oper.opr.ref.index:=actasmregister;
  136. inc(regs);
  137. end
  138. else
  139. begin
  140. Message(asmr_e_invalid_reference_syntax);
  141. RecoverConsume(true);
  142. break;
  143. end;
  144. Consume(AS_REGISTER);
  145. end;
  146. AS_ID:
  147. Begin
  148. l:=BuildConstExpression(true,true);
  149. inc(oper.opr.ref.offset,l);
  150. End;
  151. AS_RBRACKET:
  152. begin
  153. if (regs=0) and (not hasimm) then
  154. Message(asmr_e_invalid_reference_syntax);
  155. Consume(AS_RBRACKET);
  156. break;
  157. end;
  158. else
  159. Begin
  160. Message(asmr_e_invalid_reference_syntax);
  161. RecoverConsume(false);
  162. break;
  163. end;
  164. end;
  165. until false;
  166. end;
  167. procedure TSparcReader.handlepercent;
  168. var
  169. len : longint;
  170. begin
  171. len:=1;
  172. actasmpattern[len]:='%';
  173. c:=current_scanner.asmgetchar;
  174. { to be a register there must be a letter and not a number }
  175. while c in ['a'..'z','A'..'Z','0'..'9'] do
  176. Begin
  177. inc(len);
  178. actasmpattern[len]:=c;
  179. c:=current_scanner.asmgetchar;
  180. end;
  181. actasmpattern[0]:=chr(len);
  182. uppervar(actasmpattern);
  183. if is_register(actasmpattern) then
  184. exit;
  185. if (actasmpattern='%HI') then
  186. actasmtoken:=AS_HI
  187. else if (actasmpattern='%LO')then
  188. actasmtoken:=AS_LO
  189. else
  190. Message(asmr_e_invalid_register);
  191. end;
  192. Procedure TSparcReader.BuildOperand(oper : tSparcoperand);
  193. var
  194. expr : string;
  195. typesize,l : aint;
  196. procedure AddLabelOperand(hl:tasmlabel);
  197. begin
  198. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  199. is_calljmp(actopcode) then
  200. begin
  201. oper.opr.typ:=OPR_SYMBOL;
  202. oper.opr.symbol:=hl;
  203. end
  204. else
  205. begin
  206. oper.InitRef;
  207. oper.opr.ref.symbol:=hl;
  208. end;
  209. end;
  210. procedure MaybeRecordOffset;
  211. var
  212. hasdot : boolean;
  213. l,
  214. toffset,
  215. tsize : aint;
  216. begin
  217. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  218. exit;
  219. l:=0;
  220. hasdot:=(actasmtoken=AS_DOT);
  221. if hasdot then
  222. begin
  223. if expr<>'' then
  224. begin
  225. BuildRecordOffsetSize(expr,toffset,tsize);
  226. inc(l,toffset);
  227. oper.SetSize(tsize,true);
  228. end;
  229. end;
  230. if actasmtoken in [AS_PLUS,AS_MINUS] then
  231. inc(l,BuildConstExpression(true,false));
  232. case oper.opr.typ of
  233. OPR_LOCAL :
  234. begin
  235. { don't allow direct access to fields of parameters, because that
  236. will generate buggy code. Allow it only for explicit typecasting }
  237. if hasdot and
  238. (not oper.hastype) and
  239. (tabstractnormalvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
  240. (current_procinfo.procdef.proccalloption<>pocall_register) then
  241. Message(asmr_e_cannot_access_field_directly_for_parameters);
  242. inc(oper.opr.localsymofs,l)
  243. end;
  244. OPR_CONSTANT :
  245. inc(oper.opr.val,l);
  246. OPR_REFERENCE :
  247. inc(oper.opr.ref.offset,l);
  248. else
  249. internalerror(200309221);
  250. end;
  251. end;
  252. var
  253. tempreg : tregister;
  254. tempstr : string;
  255. tempsymtyp : TAsmSymType;
  256. hl : tasmlabel;
  257. gotplus,
  258. negative : boolean;
  259. Begin
  260. expr:='';
  261. gotplus:=true;
  262. negative:=false;
  263. repeat
  264. case actasmtoken of
  265. AS_MINUS :
  266. begin
  267. consume(AS_MINUS);
  268. negative:=true;
  269. gotplus:=true;
  270. end;
  271. AS_PLUS :
  272. begin
  273. consume(AS_PLUS);
  274. negative:=false;
  275. gotplus:=true;
  276. end;
  277. AS_INTNUM,
  278. AS_MOD:
  279. Begin
  280. if not gotplus then
  281. Message(asmr_e_invalid_reference_syntax);
  282. l:=BuildConstExpression(True,False);
  283. if negative then
  284. l:=-l;
  285. { Constant memory offset }
  286. oper.InitRef;
  287. oper.opr.ref.refaddr:=addr_full;
  288. oper.opr.ref.offset:=l;
  289. GotPlus:=(prevasmtoken=AS_PLUS) or
  290. (prevasmtoken=AS_MINUS);
  291. if GotPlus then
  292. negative:=(prevasmtoken=AS_MINUS);
  293. end;
  294. AS_LBRACKET :
  295. begin
  296. { memory reference }
  297. BuildReference(oper);
  298. gotplus:=false;
  299. end;
  300. AS_HI,
  301. AS_LO:
  302. begin
  303. { Low or High part of a constant (or constant
  304. memory location) }
  305. oper.InitRef;
  306. if actasmtoken=AS_LO then
  307. oper.opr.ref.refaddr:=addr_lo
  308. else
  309. oper.opr.ref.refaddr:=addr_hi;
  310. Consume(actasmtoken);
  311. Consume(AS_LPAREN);
  312. BuildConstSymbolExpression(false, true,false,l,tempstr,tempsymtyp);
  313. if not assigned(oper.opr.ref.symbol) then
  314. oper.opr.ref.symbol:=objectlibrary.newasmsymbol(tempstr,AB_EXTERNAL,tempsymtyp)
  315. else
  316. Message(asmr_e_cant_have_multiple_relocatable_symbols);
  317. case oper.opr.typ of
  318. OPR_CONSTANT :
  319. inc(oper.opr.val,l);
  320. OPR_LOCAL :
  321. inc(oper.opr.localsymofs,l);
  322. OPR_REFERENCE :
  323. inc(oper.opr.ref.offset,l);
  324. else
  325. internalerror(200309202);
  326. end;
  327. Consume(AS_RPAREN);
  328. gotplus:=false;
  329. end;
  330. AS_ID: { A constant expression, or a Variable ref. }
  331. Begin
  332. { Local Label ? }
  333. if is_locallabel(actasmpattern) then
  334. begin
  335. CreateLocalLabel(actasmpattern,hl,false);
  336. Consume(AS_ID);
  337. AddLabelOperand(hl);
  338. end
  339. else
  340. { Check for label }
  341. if SearchLabel(actasmpattern,hl,false) then
  342. begin
  343. Consume(AS_ID);
  344. AddLabelOperand(hl);
  345. end
  346. else
  347. { probably a variable or normal expression }
  348. { or a procedure (such as in CALL ID) }
  349. Begin
  350. { is it a constant ? }
  351. if SearchIConstant(actasmpattern,l) then
  352. Begin
  353. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  354. Message(asmr_e_invalid_operand_type);
  355. BuildConstantOperand(oper);
  356. end
  357. else
  358. begin
  359. expr:=actasmpattern;
  360. Consume(AS_ID);
  361. { typecasting? }
  362. if (actasmtoken=AS_LPAREN) and
  363. SearchType(expr,typesize) then
  364. begin
  365. oper.hastype:=true;
  366. Consume(AS_LPAREN);
  367. BuildOperand(oper);
  368. Consume(AS_RPAREN);
  369. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  370. oper.SetSize(typesize,true);
  371. end
  372. else
  373. begin
  374. if oper.SetupVar(expr,false) then
  375. ReadPercent(oper)
  376. else
  377. Begin
  378. { look for special symbols ... }
  379. if expr= '__HIGH' then
  380. begin
  381. consume(AS_LPAREN);
  382. if not oper.setupvar('high'+actasmpattern,false) then
  383. Message1(sym_e_unknown_id,'high'+actasmpattern);
  384. consume(AS_ID);
  385. consume(AS_RPAREN);
  386. end
  387. else
  388. if expr = '__RESULT' then
  389. oper.SetUpResult
  390. else
  391. if expr = '__SELF' then
  392. oper.SetupSelf
  393. else
  394. if expr = '__OLDEBP' then
  395. oper.SetupOldEBP
  396. else
  397. Message1(sym_e_unknown_id,expr);
  398. end;
  399. end;
  400. end;
  401. if actasmtoken=AS_DOT then
  402. MaybeRecordOffset;
  403. { add a constant expression? }
  404. if (actasmtoken=AS_PLUS) then
  405. begin
  406. l:=BuildConstExpression(true,false);
  407. case oper.opr.typ of
  408. OPR_CONSTANT :
  409. inc(oper.opr.val,l);
  410. OPR_LOCAL :
  411. inc(oper.opr.localsymofs,l);
  412. OPR_REFERENCE :
  413. inc(oper.opr.ref.offset,l);
  414. else
  415. internalerror(200309202);
  416. end;
  417. end
  418. end;
  419. gotplus:=false;
  420. end;
  421. AS_REGISTER: { Register, a variable reference or a constant reference }
  422. Begin
  423. { save the type of register used. }
  424. tempreg:=actasmregister;
  425. Consume(AS_REGISTER);
  426. if (oper.opr.typ in [OPR_REGISTER,OPR_REFERENCE]) and gotplus then
  427. begin
  428. oper.initref;
  429. oper.opr.ref.refaddr:=addr_full;
  430. if oper.opr.ref.base<>NR_NO then
  431. oper.opr.ref.base:=tempreg
  432. else
  433. if oper.opr.ref.index<>NR_NO then
  434. oper.opr.ref.index:=tempreg
  435. else
  436. Message(asmr_e_multiple_index);
  437. end
  438. else
  439. begin
  440. if (oper.opr.typ<>OPR_NONE) then
  441. Message(asmr_e_invalid_operand_type);
  442. oper.opr.typ:=OPR_REGISTER;
  443. oper.opr.reg:=tempreg;
  444. end;
  445. gotplus:=false;
  446. end;
  447. AS_END,
  448. AS_SEPARATOR,
  449. AS_COMMA:
  450. break;
  451. else
  452. Begin
  453. Message(asmr_e_syn_operand);
  454. Consume(actasmtoken);
  455. end;
  456. end; { end case }
  457. until false;
  458. end;
  459. {*****************************************************************************
  460. TSparcReader
  461. *****************************************************************************}
  462. procedure TSparcReader.BuildOpCode(instr : tSparcinstruction);
  463. var
  464. operandnum : longint;
  465. Begin
  466. { opcode }
  467. if (actasmtoken<>AS_OPCODE) then
  468. Begin
  469. Message(asmr_e_invalid_or_missing_opcode);
  470. RecoverConsume(true);
  471. exit;
  472. end;
  473. { Fill the instr object with the current state }
  474. with instr do
  475. begin
  476. Opcode:=ActOpcode;
  477. condition:=ActCondition;
  478. end;
  479. { We are reading operands, so opcode will be an AS_ID }
  480. operandnum:=1;
  481. Consume(AS_OPCODE);
  482. { Zero operand opcode ? }
  483. if actasmtoken in [AS_SEPARATOR,AS_END] then
  484. begin
  485. operandnum:=0;
  486. exit;
  487. end;
  488. { delayslot annulled? }
  489. if (actasmtoken=AS_COMMA) then
  490. begin
  491. consume(AS_COMMA);
  492. if actasmpattern='A' then
  493. instr.delayslot_annulled:=true;
  494. { force reading of AS_COMMA instead of AS_ID, otherwise
  495. a label .L0 will first read a AS_DOT instead of AS_ID }
  496. actasmtoken:=AS_COMMA;
  497. consume(AS_COMMA);
  498. end;
  499. { Read the operands }
  500. repeat
  501. case actasmtoken of
  502. AS_COMMA: { Operand delimiter }
  503. Begin
  504. if operandnum>Max_Operands then
  505. Message(asmr_e_too_many_operands)
  506. else
  507. begin
  508. { condition operands doesn't set the operand but write to the
  509. condition field of the instruction
  510. }
  511. if instr.Operands[operandnum].opr.typ<>OPR_NONE then
  512. Inc(operandnum);
  513. end;
  514. Consume(AS_COMMA);
  515. end;
  516. AS_SEPARATOR,
  517. AS_END : { End of asm operands for this opcode }
  518. begin
  519. break;
  520. end;
  521. else
  522. BuildOperand(instr.Operands[operandnum] as tSparcoperand);
  523. end; { end case }
  524. until false;
  525. if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
  526. dec(operandnum);
  527. instr.Ops:=operandnum;
  528. end;
  529. function TSparcReader.is_asmopcode(const s: string):boolean;
  530. var
  531. str2opEntry: tstr2opEntry;
  532. cond:TAsmCond;
  533. Begin
  534. { making s a value parameter would break other assembler readers }
  535. is_asmopcode:=false;
  536. { clear op code }
  537. actopcode:=A_None;
  538. { clear condition }
  539. fillchar(actcondition,sizeof(actcondition),0);
  540. str2opentry:=tstr2opentry(iasmops.search(s));
  541. if assigned(str2opentry) then
  542. begin
  543. actopcode:=str2opentry.op;
  544. actasmtoken:=AS_OPCODE;
  545. is_asmopcode:=true;
  546. end
  547. { not found, check branch instructions }
  548. else if (Upcase(s[1])='B') or
  549. ((Upcase(s[1])='F') and (Upcase(s[2])='B')) then
  550. begin
  551. { we can search here without an extra table which is sorted by string length
  552. because we take the whole remaining string without the leading B }
  553. if (Upcase(s[1])='F') then
  554. actopcode := A_FBxx
  555. else
  556. actopcode := A_Bxx;
  557. for cond:=low(TAsmCond) to high(TAsmCond) do
  558. if (Upper(copy(s,2,length(s)-1))=Upper(Cond2Str[cond])) then
  559. begin
  560. actasmtoken:=AS_OPCODE;
  561. actcondition:=cond;
  562. is_asmopcode:=true;
  563. end;
  564. end;
  565. end;
  566. procedure TSparcReader.ConvertCalljmp(instr : tSparcinstruction);
  567. var
  568. newopr : toprrec;
  569. begin
  570. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  571. with newopr do
  572. begin
  573. typ:=OPR_SYMBOL;
  574. symbol:=instr.Operands[1].opr.ref.symbol;
  575. symofs:=instr.Operands[1].opr.ref.offset;
  576. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  577. (instr.Operands[1].opr.ref.index<>NR_NO) or
  578. (instr.Operands[1].opr.ref.refaddr<>addr_full) then
  579. Message(asmr_e_syn_operand);
  580. instr.Operands[1].opr:=newopr;
  581. end;
  582. end;
  583. procedure TSparcReader.handleopcode;
  584. var
  585. instr : tSparcinstruction;
  586. begin
  587. instr:=TSparcInstruction.Create(TSparcOperand);
  588. BuildOpcode(instr);
  589. with instr do
  590. begin
  591. condition := actcondition;
  592. if is_calljmp(opcode) then
  593. ConvertCalljmp(instr);
  594. ConcatInstruction(curlist);
  595. Free;
  596. end;
  597. end;
  598. {*****************************************************************************
  599. Initialize
  600. *****************************************************************************}
  601. const
  602. asmmode_Sparc_att_info : tasmmodeinfo =
  603. (
  604. id : asmmode_Sparc_gas;
  605. idtxt : 'GAS';
  606. casmreader : TSparcReader;
  607. );
  608. asmmode_Sparc_standard_info : tasmmodeinfo =
  609. (
  610. id : asmmode_standard;
  611. idtxt : 'STANDARD';
  612. casmreader : TSparcReader;
  613. );
  614. initialization
  615. RegisterAsmMode(asmmode_Sparc_att_info);
  616. RegisterAsmMode(asmmode_Sparc_standard_info);
  617. end.
  618. {
  619. $Log$
  620. Revision 1.12 2004-11-21 15:35:23 peter
  621. * float routines all use internproc and compilerproc helpers
  622. Revision 1.11 2004/11/11 19:31:33 peter
  623. * fixed compile of powerpc,sparc,arm
  624. Revision 1.10 2004/06/20 08:55:32 florian
  625. * logs truncated
  626. Revision 1.9 2004/06/16 20:07:11 florian
  627. * dwarf branch merged
  628. Revision 1.8.2.4 2004/06/02 20:59:05 peter
  629. * fix negative consts
  630. Revision 1.8.2.3 2004/05/25 21:38:53 peter
  631. * assembler reader/writer updates
  632. Revision 1.8.2.2 2004/05/18 20:24:03 florian
  633. * fixed crash with unknown symbols
  634. Revision 1.8.2.1 2004/05/01 23:36:47 peter
  635. * assembler reader 64bit fixes
  636. }