racpugas.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. {
  2. Copyright (c) 1998-2002 by Mazen NEIFER
  3. Does the parsing for the i386 GNU AS styled inline assembler.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. Unit racpugas;
  18. {$i fpcdefs.inc}
  19. Interface
  20. uses
  21. rautils,
  22. raatt;
  23. type
  24. tMipsReader = class(tattreader)
  25. function is_asmopcode(const s: string):boolean;override;
  26. procedure BuildOperand(oper : TOperand);
  27. procedure BuildOpCode(instr : TInstruction);
  28. procedure ReadSym(oper : TOperand);
  29. procedure ConvertCalljmp(instr : TInstruction);
  30. procedure handlepercent;override;
  31. procedure handledollar;override;
  32. procedure handleopcode;override;
  33. end;
  34. Implementation
  35. uses
  36. { helpers }
  37. cutils,
  38. { global }
  39. globtype,verbose,
  40. systems,
  41. { aasm }
  42. cpubase,aasmbase,aasmtai,aasmdata,aasmcpu,
  43. { symtable }
  44. symconst,symsym,
  45. { parser }
  46. scanner,
  47. procinfo,
  48. rabase,
  49. rgbase,
  50. itcpugas,
  51. cgbase,cgobj
  52. ;
  53. procedure TMipsReader.ReadSym(oper : TOperand);
  54. var
  55. tempstr, mangledname : string;
  56. typesize,l,k : aint;
  57. begin
  58. tempstr:=actasmpattern;
  59. Consume(AS_ID);
  60. { typecasting? }
  61. if (actasmtoken=AS_LPAREN) and
  62. SearchType(tempstr,typesize) then
  63. begin
  64. oper.hastype:=true;
  65. Consume(AS_LPAREN);
  66. BuildOperand(oper);
  67. Consume(AS_RPAREN);
  68. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  69. oper.SetSize(typesize,true);
  70. end
  71. else
  72. if not oper.SetupVar(tempstr,false) then
  73. Message1(sym_e_unknown_id,tempstr);
  74. { record.field ? }
  75. if actasmtoken=AS_DOT then
  76. begin
  77. BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  78. if (mangledname<>'') then
  79. Message(asmr_e_invalid_reference_syntax);
  80. inc(oper.opr.ref.offset,l);
  81. end;
  82. end;
  83. procedure TMipsReader.handledollar;
  84. var
  85. len: longint;
  86. begin
  87. len:=1;
  88. actasmpattern[len]:='$';
  89. c:=current_scanner.asmgetchar;
  90. while c in ['A'..'Z','a'..'z','0'..'9'] do
  91. begin
  92. inc(len);
  93. actasmpattern[len]:=c;
  94. c:=current_scanner.asmgetchar;
  95. end;
  96. actasmpattern[0]:=chr(len);
  97. actasmpattern:=lower(actasmpattern);
  98. actasmregister:=gas_regnum_search(actasmpattern);
  99. if actasmregister=NR_NO then
  100. actasmregister:=std_regnum_search(copy(actasmpattern,2,maxint));
  101. actasmtoken:=AS_REGISTER;
  102. end;
  103. procedure TMipsReader.handlepercent;
  104. var
  105. len : longint;
  106. begin
  107. len:=1;
  108. actasmpattern[len]:='%';
  109. c:=current_scanner.asmgetchar;
  110. { to be a register there must be a letter and not a number }
  111. while c in ['a'..'z','A'..'Z','0'..'9'] do
  112. Begin
  113. inc(len);
  114. actasmpattern[len]:=c;
  115. c:=current_scanner.asmgetchar;
  116. end;
  117. actasmpattern[0]:=chr(len);
  118. uppervar(actasmpattern);
  119. if (actasmpattern='%HI') then
  120. actasmtoken:=AS_HI
  121. else if (actasmpattern='%LO')then
  122. actasmtoken:=AS_LO
  123. else
  124. Message(asmr_e_invalid_reference_syntax);
  125. end;
  126. Procedure TMipsReader.BuildOperand(oper : TOperand);
  127. var
  128. expr : string;
  129. typesize,l : aint;
  130. procedure AddLabelOperand(hl:tasmlabel);
  131. begin
  132. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  133. is_calljmp(actopcode) then
  134. begin
  135. oper.opr.typ:=OPR_SYMBOL;
  136. oper.opr.symbol:=hl;
  137. end
  138. else
  139. begin
  140. oper.InitRef;
  141. oper.opr.ref.symbol:=hl;
  142. end;
  143. end;
  144. procedure MaybeRecordOffset;
  145. var
  146. mangledname: string;
  147. hasdot : boolean;
  148. l,
  149. toffset,
  150. tsize : aint;
  151. begin
  152. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  153. exit;
  154. l:=0;
  155. hasdot:=(actasmtoken=AS_DOT);
  156. if hasdot then
  157. begin
  158. if expr<>'' then
  159. begin
  160. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  161. if (oper.opr.typ<>OPR_CONSTANT) and
  162. (mangledname<>'') then
  163. Message(asmr_e_wrong_sym_type);
  164. inc(l,toffset);
  165. oper.SetSize(tsize,true);
  166. end;
  167. end;
  168. if actasmtoken in [AS_PLUS,AS_MINUS] then
  169. inc(l,BuildConstExpression(true,false));
  170. case oper.opr.typ of
  171. OPR_LOCAL :
  172. begin
  173. { don't allow direct access to fields of parameters, because that
  174. will generate buggy code. Allow it only for explicit typecasting }
  175. if hasdot and
  176. (not oper.hastype) and
  177. (tabstractnormalvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
  178. (current_procinfo.procdef.proccalloption<>pocall_register) then
  179. Message(asmr_e_cannot_access_field_directly_for_parameters);
  180. inc(oper.opr.localsymofs,l)
  181. end;
  182. OPR_CONSTANT :
  183. if (mangledname<>'') then
  184. begin
  185. if (oper.opr.val<>0) then
  186. Message(asmr_e_wrong_sym_type);
  187. oper.opr.typ:=OPR_SYMBOL;
  188. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname);
  189. end
  190. else
  191. inc(oper.opr.val,l);
  192. OPR_REFERENCE :
  193. inc(oper.opr.ref.offset,l);
  194. OPR_SYMBOL:
  195. Message(asmr_e_invalid_symbol_ref);
  196. else
  197. internalerror(200309221);
  198. end;
  199. end;
  200. var
  201. tempreg : tregister;
  202. tempstr : string;
  203. tempsymtyp : TAsmSymType;
  204. hl : tasmlabel;
  205. gotplus,
  206. negative : boolean;
  207. Begin
  208. expr:='';
  209. gotplus:=true;
  210. negative:=false;
  211. repeat
  212. case actasmtoken of
  213. AS_MINUS :
  214. begin
  215. consume(AS_MINUS);
  216. negative:=true;
  217. gotplus:=true;
  218. end;
  219. AS_PLUS :
  220. begin
  221. consume(AS_PLUS);
  222. negative:=false;
  223. gotplus:=true;
  224. end;
  225. AS_INTNUM,
  226. AS_MOD:
  227. Begin
  228. if not gotplus then
  229. Message(asmr_e_invalid_reference_syntax);
  230. l:=BuildConstExpression(True,False);
  231. if negative then
  232. l:=-l;
  233. { Constant memory offset }
  234. oper.InitRef;
  235. oper.opr.ref.refaddr:=addr_full;
  236. oper.opr.ref.offset:=l;
  237. GotPlus:=(prevasmtoken=AS_PLUS) or
  238. (prevasmtoken=AS_MINUS);
  239. if GotPlus then
  240. negative:=(prevasmtoken=AS_MINUS);
  241. end;
  242. AS_LPAREN :
  243. begin
  244. consume(AS_LPAREN);
  245. oper.InitRef;
  246. if actasmtoken=AS_REGISTER then
  247. oper.opr.ref.base:=actasmregister;
  248. consume(AS_REGISTER);
  249. consume(AS_RPAREN);
  250. gotplus:=false;
  251. end;
  252. AS_HI,
  253. AS_LO:
  254. begin
  255. { Low or High part of a constant (or constant
  256. memory location) }
  257. oper.InitRef;
  258. if actasmtoken=AS_LO then
  259. oper.opr.ref.refaddr:=addr_low
  260. else
  261. oper.opr.ref.refaddr:=addr_high;
  262. Consume(actasmtoken);
  263. Consume(AS_LPAREN);
  264. BuildConstSymbolExpression(false, true,false,l,tempstr,tempsymtyp);
  265. if not assigned(oper.opr.ref.symbol) then
  266. oper.opr.ref.symbol:=current_asmdata.RefAsmSymbol(tempstr)
  267. else
  268. Message(asmr_e_cant_have_multiple_relocatable_symbols);
  269. case oper.opr.typ of
  270. OPR_CONSTANT :
  271. inc(oper.opr.val,l);
  272. OPR_LOCAL :
  273. inc(oper.opr.localsymofs,l);
  274. OPR_REFERENCE :
  275. inc(oper.opr.ref.offset,l);
  276. else
  277. internalerror(200309202);
  278. end;
  279. Consume(AS_RPAREN);
  280. gotplus:=false;
  281. end;
  282. AS_ID: { A constant expression, or a Variable ref. }
  283. Begin
  284. { Local Label ? }
  285. if is_locallabel(actasmpattern) then
  286. begin
  287. CreateLocalLabel(actasmpattern,hl,false);
  288. Consume(AS_ID);
  289. AddLabelOperand(hl);
  290. end
  291. else
  292. { Check for label }
  293. if SearchLabel(actasmpattern,hl,false) then
  294. begin
  295. Consume(AS_ID);
  296. AddLabelOperand(hl);
  297. end
  298. else
  299. { probably a variable or normal expression }
  300. { or a procedure (such as in CALL ID) }
  301. Begin
  302. { is it a constant ? }
  303. if SearchIConstant(actasmpattern,l) then
  304. Begin
  305. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  306. Message(asmr_e_invalid_operand_type);
  307. BuildConstantOperand(oper);
  308. end
  309. else
  310. begin
  311. expr:=actasmpattern;
  312. Consume(AS_ID);
  313. { typecasting? }
  314. if (actasmtoken=AS_LPAREN) and
  315. SearchType(expr,typesize) then
  316. begin
  317. oper.hastype:=true;
  318. Consume(AS_LPAREN);
  319. BuildOperand(oper);
  320. Consume(AS_RPAREN);
  321. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  322. oper.SetSize(typesize,true);
  323. end
  324. else
  325. begin
  326. if not oper.SetupVar(expr,false) then
  327. Begin
  328. { look for special symbols ... }
  329. if expr= '__HIGH' then
  330. begin
  331. consume(AS_LPAREN);
  332. if not oper.setupvar('high'+actasmpattern,false) then
  333. Message1(sym_e_unknown_id,'high'+actasmpattern);
  334. consume(AS_ID);
  335. consume(AS_RPAREN);
  336. end
  337. else
  338. if expr = '__RESULT' then
  339. oper.SetUpResult
  340. else
  341. if expr = '__SELF' then
  342. oper.SetupSelf
  343. else
  344. if expr = '__OLDEBP' then
  345. oper.SetupOldEBP
  346. else
  347. Message1(sym_e_unknown_id,expr);
  348. end;
  349. end;
  350. end;
  351. if actasmtoken=AS_DOT then
  352. MaybeRecordOffset;
  353. { add a constant expression? }
  354. if (actasmtoken=AS_PLUS) then
  355. begin
  356. l:=BuildConstExpression(true,false);
  357. case oper.opr.typ of
  358. OPR_CONSTANT :
  359. inc(oper.opr.val,l);
  360. OPR_LOCAL :
  361. inc(oper.opr.localsymofs,l);
  362. OPR_REFERENCE :
  363. inc(oper.opr.ref.offset,l);
  364. else
  365. internalerror(200309202);
  366. end;
  367. end
  368. end;
  369. gotplus:=false;
  370. end;
  371. AS_REGISTER: { Register, a variable reference or a constant reference }
  372. Begin
  373. { save the type of register used. }
  374. tempreg:=actasmregister;
  375. Consume(AS_REGISTER);
  376. begin
  377. if (oper.opr.typ<>OPR_NONE) then
  378. Message(asmr_e_invalid_operand_type);
  379. oper.opr.typ:=OPR_REGISTER;
  380. oper.opr.reg:=tempreg;
  381. end;
  382. gotplus:=false;
  383. end;
  384. AS_END,
  385. AS_SEPARATOR,
  386. AS_COMMA:
  387. break;
  388. else
  389. Begin
  390. Message(asmr_e_syn_operand);
  391. Consume(actasmtoken);
  392. end;
  393. end; { end case }
  394. until false;
  395. end;
  396. {*****************************************************************************
  397. TMipsReader
  398. *****************************************************************************}
  399. procedure TMipsReader.BuildOpCode(instr : TInstruction);
  400. var
  401. operandnum : longint;
  402. Begin
  403. { opcode }
  404. if (actasmtoken<>AS_OPCODE) then
  405. Begin
  406. Message(asmr_e_invalid_or_missing_opcode);
  407. RecoverConsume(true);
  408. exit;
  409. end;
  410. { Fill the instr object with the current state }
  411. with instr do
  412. begin
  413. Opcode:=ActOpcode;
  414. condition:=ActCondition;
  415. end;
  416. { We are reading operands, so opcode will be an AS_ID }
  417. operandnum:=1;
  418. Consume(AS_OPCODE);
  419. { Zero operand opcode ? }
  420. if actasmtoken in [AS_SEPARATOR,AS_END] then
  421. begin
  422. operandnum:=0;
  423. exit;
  424. end;
  425. { Read the operands }
  426. repeat
  427. case actasmtoken of
  428. AS_COMMA: { Operand delimiter }
  429. Begin
  430. if operandnum>Max_Operands then
  431. Message(asmr_e_too_many_operands)
  432. else
  433. begin
  434. { condition operands doesn't set the operand but write to the
  435. condition field of the instruction
  436. }
  437. if instr.Operands[operandnum].opr.typ<>OPR_NONE then
  438. Inc(operandnum);
  439. end;
  440. Consume(AS_COMMA);
  441. end;
  442. AS_SEPARATOR,
  443. AS_END : { End of asm operands for this opcode }
  444. begin
  445. break;
  446. end;
  447. else
  448. BuildOperand(instr.Operands[operandnum] as TOperand);
  449. end; { end case }
  450. until false;
  451. if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
  452. dec(operandnum);
  453. instr.Ops:=operandnum;
  454. end;
  455. function TMipsReader.is_asmopcode(const s: string):boolean;
  456. var
  457. cond:TAsmCond;
  458. hs:string;
  459. Begin
  460. is_asmopcode:=false;
  461. { clear op code and condition }
  462. actopcode:=A_None;
  463. actcondition:=C_None;
  464. { Search opcodes }
  465. actopcode:=tasmop(PtrUInt(iasmops.Find(s)));
  466. if actopcode<>A_NONE then
  467. begin
  468. actasmtoken:=AS_OPCODE;
  469. result:=TRUE;
  470. exit;
  471. end;
  472. { not found, check branch instructions }
  473. if (Upcase(s[1])='B') then
  474. begin
  475. { we can search here without an extra table which is sorted by string length
  476. because we take the whole remaining string without the leading B }
  477. actopcode := A_BC;
  478. hs:=lower(copy(s,2,maxint));
  479. for cond:=low(TAsmCond) to high(TAsmCond) do
  480. if (hs=Cond2Str[cond]) then
  481. begin
  482. actasmtoken:=AS_OPCODE;
  483. actcondition:=cond;
  484. is_asmopcode:=true;
  485. end;
  486. end;
  487. end;
  488. procedure TMipsReader.ConvertCalljmp(instr : TInstruction);
  489. var
  490. newopr : toprrec;
  491. begin
  492. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  493. with newopr do
  494. begin
  495. typ:=OPR_SYMBOL;
  496. symbol:=instr.Operands[1].opr.ref.symbol;
  497. symofs:=instr.Operands[1].opr.ref.offset;
  498. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  499. (instr.Operands[1].opr.ref.index<>NR_NO) or
  500. (instr.Operands[1].opr.ref.refaddr<>addr_full) then
  501. Message(asmr_e_syn_operand);
  502. instr.Operands[1].opr:=newopr;
  503. end;
  504. end;
  505. procedure TMipsReader.handleopcode;
  506. var
  507. instr : TInstruction;
  508. begin
  509. instr:=TInstruction.Create(TOperand);
  510. BuildOpcode(instr);
  511. with instr do
  512. begin
  513. condition := actcondition;
  514. if is_calljmp(opcode) then
  515. ConvertCalljmp(instr);
  516. { Coprocessor-related instructions have operands referring to both coprocessor registers
  517. and general-purpose ones. The input representation "$<number>" is the same for both,
  518. but symbolic names must not be used for non-GPRs on output. }
  519. if (opcode in [A_MTC0,A_MFC0,A_CFC1,A_CTC1{,A_CFC2,A_CTC2}]) then
  520. begin
  521. { operands are 1-based here }
  522. if (ops<2) or (operands[2].opr.typ<>OPR_REGISTER) then
  523. message(asmr_e_syn_operand);
  524. operands[2].opr.reg:=newreg(R_SPECIALREGISTER,getsupreg(operands[2].opr.reg),R_SUBNONE);
  525. end;
  526. ConcatInstruction(curlist);
  527. Free;
  528. end;
  529. end;
  530. {*****************************************************************************
  531. Initialize
  532. *****************************************************************************}
  533. const
  534. asmmode_mips_att_info : tasmmodeinfo =
  535. (
  536. id : asmmode_standard;
  537. idtxt : 'GAS';
  538. casmreader : TMipsReader;
  539. );
  540. initialization
  541. RegisterAsmMode(asmmode_mips_att_info);
  542. end.