GCC后端及汇编发布(27)
来源:互联网 发布:vb status() 编辑:程序博客网 时间:2024/06/09 19:38
9.5.8.4. 构建有限状态自动机
有限状态自动机(FSA)被分类为确定性(DFA)及非确定性(NDFA)。对于确定性的自动机,通过初始状态及触发事件,我们可以确切地知道将要迁移到的状态;而对于非确定性自动机,则将通向多个目标。在机器描述文件里,对于指令而言,包含替代(“|”操作符)的单元预订,将引入非确定性FSA。
不过,我们可以在产生这个自动机的过程中,通过使用“-ndfa”选项来控制这些替代的输出。默认的,没有这个选项,替代以确定性的方式来处理,仅考虑到第一个合格替代的迁移。而使用这个选项,所有合格的替代都被用于构造非确定性自动机。不过在这之后,执行一个NDFA到DFA的转换,使自动机成为DFA。显然,由ndfa_flag为0所生成的自动机,效率上不如由ndfa_flag为1所生成的自动机,不过前者可以更快地生成,而且效率的损失没有想象的那么大。
6401 static void
6402 build_automaton (automaton_tautomaton) in genautomata.c
6403 {
6404 int states_num;
6405 int arcs_num;
6406
6407 ticker_on (&NDFA_time);
6408 if (progress_flag)
6409 {
6410 if (automaton->corresponding_automaton_decl== NULL)
6411 fprintf (stderr, "Create anonymousautomaton");
6412 else
6413 fprintf (stderr, "Create automaton`%s'",
6414 automaton->corresponding_automaton_decl->name);
6415 fprintf (stderr, " (1 dot is 100 newstates):");
6416 }
6417 make_automaton(automaton);
make_automaton被调用来构建自动机,它将根据“-ndfa”选项,依据出现的替代(在define_insn_reservation中的操作符“|”)构建非确定性或确定性自动机。
5693 static void
5694 make_automaton (automaton_tautomaton) in genautomata.c
5695 {
5696 ainsn_t ainsn;
5697 structinsn_reserv_decl *insn_reserv_decl;
5698 alt_state_talt_state;
5699 state_t state;
5700 state_t start_state;
5701 state_t state2;
5702 ainsn_t advance_cycle_ainsn;
5703 arc_t added_arc;
5704 vla_ptr_t state_stack;
5705 int states_n;
5706 reserv_sets_t reservs_matter = form_reservs_matter (automaton);
5707
5708 VLA_PTR_CREATE (state_stack, 150, "statestack");
5709 /* Create the startstate (empty state). */
5710 start_state = insert_state (get_free_state(1, automaton));
5711 automaton->start_state = start_state;
5712 start_state->it_was_placed_in_stack_for_NDFA_forming = 1;
5713 VLA_PTR_ADD (state_stack, start_state);
5714 states_n = 1;
在这里,form_reserv_matter将再次填充一个单元预订位图。不过,这一次的位图是与自动机一一对应的。在DEFINE_INSN_RESERVATION模式的概览一节,我们看到功能单元是需要分配给自动机的(通过define_cpu_unit模式分配,每个功能单元只能属于一个自动机),而同一个自动机的不同功能单元之间,又存在依存或互斥的关系(通过EXCLUSION_SET等模式定义)。
另外,define_insn_reservation描述了每个指令类别(注意,严格来讲,名字中insn代表的是指令类别)对功能单元的占用情况,汇总每个类别的信息,就能大致知道每个单元的总体预订的情况,这正是前一节所做的事情。
前面反映每个指令类别CPU周期中单元预订情况的位图,无法显示这些信息。这里需要把这些信息收集到与自动机对应的位图。
5669 static reserv_sets_t
5670 form_reservs_matter (automaton_t automaton) ingenautomata.c
5671 {
5672 int cycle, unit;
5673 reserv_sets_t reservs_matter =alloc_empty_reserv_sets();
5674
5675 for (cycle =0; cycle < max_cycles_num;cycle++)
5676 for (unit =0; unit < description->units_num;unit++)
5677 if (units_array [unit]->automaton_decl
5678 ==automaton->corresponding_automaton_decl
5679 && (cycle >= units_array[unit]->min_occ_cycle_num
5680 /* Wecan not remove queried unit from reservations. */
5681 || units_array [unit]->query_p
5682 /* Wecan not remove units which are used
5683 `exclusion_set', `presence_set',
5684 `final_presence_set', `absence_set', and
5685 `final_absence_set'. */
5686 || units_array [unit]->in_set_p))
5687 set_unit_reserv(reservs_matter, cycle, unit);
5688 returnreservs_matter;
5689 }
在5679行的min_occ_cycle_num反映了该单元所有预订中,最小的预订周期。在这里的处理中,之后的周期,该单元都将被所属自动机视为已预订。这样做显然很保守,但足够简单并且正确。
接着在make_automaton的5710行,一个新的start_state被保存入state_stack。它将是这个构建中的自动机的起始点。因此5715行条件一开始就满足了。
make_automaton (continued)
5715 while(VLA_PTR_LENGTH (state_stack) != 0)
5716 {
5717 state = VLA_PTR (state_stack,VLA_PTR_LENGTH (state_stack) - 1);
5718 VLA_PTR_SHORTEN (state_stack, 1);
5719 advance_cycle_ainsn = NULL;
5720 for (ainsn = automaton->ainsn_list;
5721 ainsn != NULL;
5722 ainsn = ainsn->next_ainsn)
5723 if(ainsn->first_insn_with_same_reservs)
5724 {
5725 insn_reserv_decl =ainsn->insn_reserv_decl;
5726 if (insn_reserv_decl !=DECL_INSN_RESERV (advance_cycle_insn_decl))
5727 {
5728 /* Weprocess alt_states in the same order as they are
5729 present in the description. */
5730 added_arc = NULL;
5731 for (alt_state = ainsn->alt_states;
5732 alt_state != NULL;
5733 alt_state =alt_state->next_alt_state)
5734 {
5735 state2 = alt_state->state;
5736 if (!intersected_state_reservs_p (state,state2))
5737 {
5738 state2 = states_union(state, state2, reservs_matter);
5739 if(!state2->it_was_placed_in_stack_for_NDFA_forming)
5740 {
5741 state2->it_was_placed_in_stack_for_NDFA_forming
5742 = 1;
5743 VLA_PTR_ADD (state_stack,state2);
5744 states_n++;
5745 if (progress_flag && states_n %100 == 0)
5746 fprintf (stderr, ".");
5747 }
5748 added_arc = add_arc(state, state2, ainsn, 1);
5749 if (!ndfa_flag)
5750 break;
5751 }
5752 }
5753 if (!ndfa_flag && added_arc !=NULL)
5754 {
5755 added_arc->state_alts = 0;
5756 for (alt_state = ainsn->alt_states;
5757 alt_state != NULL;
5758 alt_state =alt_state->next_alt_state)
5759 {
5760 state2 = alt_state->state;
5761 if (!intersected_state_reservs_p (state,state2))
5762 added_arc->state_alts++;
5763 }
5764 }
5765 }
5766 else
5767 advance_cycle_ainsn = ainsn;
5768 }
5769 /* Addtransition to advance cycle. */
5770 state2 = state_shift (state,reservs_matter);
5771 if(!state2->it_was_placed_in_stack_for_NDFA_forming)
5772 {
5773 state2->it_was_placed_in_stack_for_NDFA_forming = 1;
5774 VLA_PTR_ADD (state_stack, state2);
5775 states_n++;
5776 if (progress_flag && states_n % 100 == 0)
5777 fprintf (stderr, ".");
5778 }
5779 if (advance_cycle_ainsn == NULL)
5780 abort ();
5781 add_arc (state,state2, advance_cycle_ainsn, 1);
5782 }
5783 VLA_PTR_DELETE (state_stack);
5784 }
在这个自动机中,我们使用状态来追踪资源的使用,状态的迁移显示指令的发布。有两种状态迁移。第一种,某些指令可以在这个状态下发布(即,该指令不会与已发布的指令争夺资源)。另一种,如果没有指令可以被发布,我们不能做任何事,等待CPU前进一个周期。
在前面的小节中,已经看到ainsn如果设置了first_insn_with_same_reservs,表明它是使用该单元预订的在机器描述文件中第一个出现的define_insn_reservation模式。这意味着这个模式所预订的单元可能可用,值得做一次查找。而如果first_insn_with_same_reservs为0,则意味着已经安排了使用同样单元的其它的指令类别,只能等下一个周期了(跳到5770行)。
上面在5761行,state代表源状态,state2则是可能的目标状态,注意这两个状态在同一个周期中,它们必须不争夺相同的CPU单元,迁移才有可能。intersected_state_reservs_p就是检查这两个状态是否会争夺相同的资源,它返回0,如果没有发现资源的争夺。
4168 static int
4169 intersected_state_reservs_p (state_t state1, state_t state2) in genautomata.c
4170 {
4171 if (state1->automaton !=state2->automaton)
4172 abort ();
4173 return reserv_sets_are_intersected(state1->reservs, state2->reservs);
4174 }
显而易见,这两个状态必须属于同一个自动机。在state中reservs域是记录这个状态下各个周期里对功能单元的占用情况的位图(周期数取决于所有define_insn_reservation模式中出现的最大周期数),因此满足3881行条件,表示这两个状态有冲突。
3867 static int
3868 reserv_sets_are_intersected(reserv_sets_t operand_1, ingenautomata.c
3869 reserv_sets_t operand_2)
3870 {
3871 set_el_t *el_ptr_1;
3872 set_el_t *el_ptr_2;
3873 set_el_t *cycle_ptr_1;
3874 set_el_t *cycle_ptr_2;
3875
3876 if(operand_1 == NULL || operand_2 == NULL)
3877 abort ();
3878 for (el_ptr_1 = operand_1, el_ptr_2 = operand_2;
3879 el_ptr_1 < operand_1 + els_in_reservs;
3880 el_ptr_1++, el_ptr_2++)
3881 if (*el_ptr_1 & *el_ptr_2)
3882 return 1;
3883 reserv_sets_or (temp_reserv, operand_1, operand_2);
3884 for(cycle_ptr_1 = operand_1, cycle_ptr_2 = operand_2;
3885 cycle_ptr_1 < operand_1 + els_in_reservs;
3886 cycle_ptr_1 += els_in_cycle_reserv, cycle_ptr_2 +=els_in_cycle_reserv)
3887 {
3888 for(el_ptr_1 = cycle_ptr_1, el_ptr_2 = get_excl_set(cycle_ptr_2);
3889 el_ptr_1 < cycle_ptr_1 + els_in_cycle_reserv;
3890 el_ptr_1++, el_ptr_2++)
3891 if (*el_ptr_1 & *el_ptr_2)
3892 return 1;
3893 if (!check_presence_pattern_sets(cycle_ptr_1, cycle_ptr_2, FALSE))
3894 return 1;
3895 if (!check_presence_pattern_sets (temp_reserv+ (cycle_ptr_2
3896 - operand_2),
3897 cycle_ptr_2,TRUE))
3898 return 1;
3899 if (!check_absence_pattern_sets(cycle_ptr_1, cycle_ptr_2, FALSE))
3900 return 1;
3901 if (!check_absence_pattern_sets (temp_reserv+ (cycle_ptr_2 - operand_2),
3902 cycle_ptr_2,TRUE))
3903 return 1;
3904 }
3905 return 0;
3906 }
如果这两个状态不竞争资源,那么离下结论还为时过早,我们需要进一步检查功能单元之间是否由于依存、互斥关系导致冲突。
首先检查单元互斥的状况。在initiate_excl_sets中根据出现的EXCLUDE_SET模式(参见数据初始化一节)设置unit_excl_set_table。这也是个位图,它的实现是一个unit_num * unit_num的二维数组(因为互斥是对称关系,它实际上是一个对称矩阵),互斥的单元1及2,在数组1*2处为1。
4582 static reserv_sets_t
4583 get_excl_set (reserv_sets_t in_set)
4584 {
4585 int excl_char_num;
4586 int chars_num;
4587 int i;
4588 int start_unit_num;
4589 int unit_num;
4590
4591 chars_num = els_in_cycle_reserv * sizeof (set_el_t);
4592 memset (excl_set, 0, chars_num);
4593 for(excl_char_num = 0; excl_char_num < chars_num; excl_char_num++)
4594 if (((unsigned char *) in_set)[excl_char_num])
4595 for (i = CHAR_BIT - 1; i >= 0; i--)
4596 if ((((unsigned char *) in_set)[excl_char_num] >> i) & 1)
4597 {
4598 start_unit_num = excl_char_num * CHAR_BIT +i;
4599 if (start_unit_num >= description->units_num)
4600 return excl_set;
4601 for(unit_num = 0; unit_num < els_in_cycle_reserv; unit_num++)
4602 {
4603 excl_set [unit_num]
4604 |= unit_excl_set_table[start_unit_num] [unit_num];
4605 }
4606 }
4607 return excl_set;
4608 }
在4594及4596行,只有被预订的单元才去查找与其互斥的单元,结果放在数组excl_set中,这个数组的元素也是位图。这个位图是编号为其索引的单元与其它单元的互斥位图。显然如果相斥的单元出现在另一个状态中,这两个状态是不可以合并的。
除了互斥关系,还要检查依赖关系。在3883行,首先获取这两个状态的合并状态,结果保存在temp_reserv中。在DEFINE_INSN_RESERVATION模式的概览一节里,我们知道presence及absence依赖关系有final及非final的区别。Final版本的要求在目的状态进行检查,非final则在源状态进行检查,temp_reserv就作为假定的目的状态。上面表达式“temp_reserv + (cycle_ptr_2 - operand_2)”是相应周期假定的目的状态对单元占用位图。
check_presence_pattern_sets的任务相当清楚,根据在original_set中被预订的单元,在unit_final_presence_set_table或unit_presence_set_table中查找其所依赖的单元。如果所依赖的单元都出现在checked_set中,那么这两个状态可能是相容的。
4692 static int
4693 check_presence_pattern_sets (reserv_sets_tchecked_set,
4694 reserv_sets_t origional_set,
4695 int final_p)
4696 {
4697 int char_num;
4698 int chars_num;
4699 int i;
4700 int start_unit_num;
4701 int unit_num;
4702 int presence_p;
4703 pattern_reserv_t pat_reserv;
4704
4705 chars_num = els_in_cycle_reserv * sizeof (set_el_t);
4706 for (char_num= 0; char_num < chars_num; char_num++)
4707 if (((unsigned char *) origional_set)[char_num])
4708 for (i =CHAR_BIT - 1; i >= 0; i--)
4709 if ((((unsigned char *) origional_set)[char_num] >> i) & 1)
4710 {
4711 start_unit_num = char_num * CHAR_BIT + i;
4712 if (start_unit_num >= description->units_num)
4713 break;
4714 if ((final_p
4715 && unit_final_presence_set_table[start_unit_num] == NULL)
4716 || (!final_p
4717 && unit_presence_set_table[start_unit_num] == NULL))
4718 continue;
4719 presence_p = FALSE;
4720 for (pat_reserv = (final_p
4721 ? unit_final_presence_set_table [start_unit_num]
4722 : unit_presence_set_table [start_unit_num]);
4723 pat_reserv != NULL;
4724 pat_reserv =pat_reserv->next_pattern_reserv)
4725 {
4726 for(unit_num = 0; unit_num < els_in_cycle_reserv; unit_num++)
4727 if((checked_set [unit_num] & pat_reserv->reserv [unit_num])
4728 != pat_reserv->reserv [unit_num])
4729 break;
4730 presence_p = presence_p || unit_num>= els_in_cycle_reserv;
4731 }
4732 if (!presence_p)
4733 returnFALSE;
4734 }
4735 return TRUE;
4736 }
check_absence_pattern_sets的处理亦如是,只有所有不能出现的单元都不在checked_set中出现,这两个状态才可能相容。
4741 static int
4742 check_absence_pattern_sets (reserv_sets_tchecked_set,
4743 reserv_sets_t origional_set,
4744 int final_p)
4745 {
4746 int char_num;
4747 int chars_num;
4748 int i;
4749 int start_unit_num;
4750 int unit_num;
4751 pattern_reserv_t pat_reserv;
4752
4753 chars_num = els_in_cycle_reserv * sizeof (set_el_t);
4754 for (char_num= 0; char_num < chars_num; char_num++)
4755 if (((unsigned char *) origional_set)[char_num])
4756 for (i =CHAR_BIT - 1; i >= 0; i--)
4757 if ((((unsigned char *) origional_set)[char_num] >> i) & 1)
4758 {
4759 start_unit_num = char_num * CHAR_BIT + i;
4760 if (start_unit_num >= description->units_num)
4761 break;
4762 for (pat_reserv= (final_p
4763 ? unit_final_absence_set_table [start_unit_num]
4764 : unit_absence_set_table [start_unit_num]);
4765 pat_reserv != NULL;
4766 pat_reserv = pat_reserv->next_pattern_reserv)
4767 {
4768 for(unit_num = 0; unit_num < els_in_cycle_reserv; unit_num++)
4769 if ((checked_set [unit_num] &pat_reserv->reserv [unit_num])
4770 != pat_reserv->reserv [unit_num]
4771 && pat_reserv->reserv[unit_num])
4772 break;
4773 if (unit_num >= els_in_cycle_reserv)
4774 return FALSE;
4775 }
4776 }
4777 return TRUE;
4778 }
如果状态可以合并,在5738行,state_union把它们合并为一个新状态。然后这个新状态放入state_stack,作为下一步的起点。
4179 static state_t
4180 states_union (state_t state1, state_tstate2, reserv_sets_t reservs)
4181 {
4182 state_t result;
4183 state_t state_in_table;
4184
4185 if (state1->automaton !=state2->automaton)
4186 abort ();
4187 result = get_free_state (1,state1->automaton);
4188 reserv_sets_or (result->reservs,state1->reservs, state2->reservs);
4189 reserv_sets_and (result->reservs,result->reservs, reservs);
4190 state_in_table = insert_state (result);
4191 if (result != state_in_table)
4192 {
4193 free_state (result);
4194 result = state_in_table;
4195 }
4196 returnresult;
4197 }
上面参数reservs是由form_reservs_matter构建的,自动机对功能单元的占用情况。两个状态的合集可能超出了自动机占用的单元,所以要在4189行进行与操作。
接着,我们需要记录到这个新状态的迁移。
4319 static arc_t
4320 add_arc (state_tfrom_state, state_t to_state, ainsn_t ainsn, in genautomata.c
4321 int state_alts)
4322 {
4323 arc_t new_arc;
4324
4325 new_arc = find_arc(from_state, to_state, ainsn);
4326 if (new_arc != NULL)
4327 returnnew_arc;
4328 if (first_free_arc == NULL)
4329 {
4330 #ifndef NDEBUG
4331 allocated_arcs_num++;
4332 #endif
4333 new_arc = create_node (sizeof (struct arc));
4334 new_arc->to_state = NULL;
4335 new_arc->insn = NULL;
4336 new_arc->next_out_arc = NULL;
4337 }
4338 else
4339 {
4340 new_arc = first_free_arc;
4341 first_free_arc = first_free_arc->next_out_arc;
4342 }
4343 new_arc->to_state = to_state;
4344 new_arc->insn = ainsn;
4345 ainsn->arc_exists_p = 1;
4346 new_arc->next_out_arc =from_state->first_out_arc;
4347 from_state->first_out_arc = new_arc;
4348 new_arc->next_arc_marked_by_insn = NULL;
4349 new_arc->state_alts = state_alts;
4350 returnnew_arc;
4351 }
Arc被定义为如下。对于所有外出的to_state,它们由next_out_arc链接起来,而to_state代表迁移的目标。
1140 struct arc in genautomata.c
1141 {
1142 /* The followingfield refers for the state into which given arc
1143 enters. */
1144 state_t to_state;
1145 /* The followingfield describes that the insn issue (with cycle
1146 advancing for special insn `cycleadvancing' and without cycle
1147 advancing for others) makes transition fromgiven state to
1148 another given state. */
1149 ainsn_t insn;
1150 /* The followingfield value is the next arc output from the same
1151 state. */
1152 arc_t next_out_arc;
1153 /* List of arcsmarked given insn is formed with the following
1154 field. The field is used in transformationNDFA -> DFA. */
1155 arc_t next_arc_marked_by_insn;
1156 /* The followingfield is defined if NDFA_FLAG is zero. The member
1157 value is number of alternative reservationswhich can be used for
1158 transition for given state by giveninsn. */
1159 int state_alts;
1160 };
Arc的对象必须与(sourcestate,target state,insn)对严格的一一对应。这一决定对后面自动机最小化有深刻的影响。这个唯一性由find_arc保证。
4305 static arc_t
4306 find_arc (state_t from_state, state_t to_state, ainsn_t insn)
4307 {
4308 arc_t arc;
4309
4310 for (arc =first_out_arc (from_state); arc != NULL; arc = next_out_arc (arc))
4311 if (arc->to_state == to_state &&arc->insn == insn)
4312 returnarc;
4313 return NULL;
4314 }
上面在5749行,ndfa_flag如果非0,表明使用“-ndfa”选项(以非确定性方式处理替代)。在非确定性方式中,对于一个define_insn_reservation的所有替代,将记录每个可能迁移;而在确定性方式中,对于一个define_insn_reservation的所有替代,仅记录第一个合格的替代,及可能迁移的数目(不过第一个以外的迁移是不会被采用的)。例如,假定一个define_insn_reservation具有三个替代:A,B及C。从开始状态S开始,我们得到以下的arcs:
S à A(可以迁移,构建状态SA,压入state_stack)
S à B(可以迁移,构建状态SB,压入state_stack)
S à C(可以迁移,构建状态SC,压入state_stack)
而在确定性自动机中,将为第一个可能的迁移创建一个arc。在这个例子中,我们可以得到:
S à A(可以迁移,构建状态SA,压入state_stack),及arc的state_alts的值为3。
假定接下来的define_insn_reservation具有两个替代:E及F。对于非确定性自动机,我们得到:
S à E(可以迁移,构建状态SE,压入state_stack)
S à F(可以迁移,构建状态SF,压入state_stack)
而对于确定性自动机,我们得到:
S à E(可以迁移,构建状态SE,压入state_stack),及arc的state_alts的值为2。
在5720行的FOR循环尝试找出所有可能的迁移。那么在make_automaton的5769行,state_shift将通过移动reservs域的内容,把当前状态推进一个周期——当然,应该为这个迁移构建一个新状态及arc对象。一旦建立,这个状态(这里是state2)将被加入state_stack,作为后面的开始状态(现在在state_stack中有:对非确定性自动机,SA,SB,SC,SE,SF;对确定性自动机,SA,SE。注意这里没有state2,因为start_state∪SA = SA)。
在5715行WHILE循环的第二次运行中,从获取state_stack状态SF。 对于非确定性自动机,我们得到以下迁移,并且记住,替代必须在有效的自动机声明中共享某些CPU单元:
F à E(不可能,intersected_state_reservs_p返回1)
F à A(构建状态FA,压入state_stack,假定没有CPU单元冲突)
F à B(构建状态FB,压入state_stack,假定没有CPU单元冲突)
F à C(构建状态FC,压入state_stack,假定没有CPU单元冲突)
F à F1(前进一个周期,构建状态F1,压入state_stack)
而对于确定性自动机我们得到以下迁移:
F à E(不可能,intersected_state_reservs_p返回1)
F à A(构建状态FA,压入state_stack,假定没有CPU单元冲突)
F à F1(前进一个周期,构建状态F1,压入state_stack)
那么在下一次循环中,获取了F1状态,我们将得到如下迁移:
F1 à A(不可能,假定intersected_state_reservs_p返回1)
F1 à B(不可能,假定intersected_state_reservs_p返回1)
F1 à C(构建状态F1C,压入state_stack,假定没有CPU单元冲突)
F1 à E(不可能,假定intersected_state_reservs_p返回1)
F1 à F(不可能,假定intersected_state_reservs_p返回1)
F1 à F2(推进F1一个周期,构建状态F2,压入state_stack)
而对于确定性自动机,获取状态E,我们将得到如下迁移:
F1 à A(不可能,假定intersected_state_reservs_p返回1)
F1 à B(不可能,假定intersected_state_reservs_p返回1)
F1 à C(构建状态F1C,压入state_stack,假定没有CPU单元冲突)
F1 à E(不可能,假定intersected_state_reservs_p返回1)
F1 à F(不可能,假定intersected_state_reservs_p返回1)
F1 à F2(推进F1一个周期,构建状态F2,压入state_stack)
此时,arc被由add_arc链接入state,我们可以得到如下视图。在这个图形中,arc*记录了迁移的信息,域next_out_arc链接起所有从相同状态出发的迁移,而域to_state指向目的状态。
图73:构建DFA,阶段1
通过这个方式,找出,并由arc记录所有的迁移机会。就通常的认识而言,我们已经构建了这个自动机。不过,如果出现的替代,NDFA可能被通过使用“-ndfa”选项构建了。NDFA不是我们所希望的,接着我们需要把它转换为DFA。
- GCC后端及汇编发布(27)
- GCC后端及汇编发布(1)
- GCC后端及汇编发布(2)
- GCC后端及汇编发布(3)
- GCC后端及汇编发布(4)
- GCC后端及汇编发布(5)
- GCC后端及汇编发布(6)
- GCC后端及汇编发布(7)
- GCC后端及汇编发布(8)
- GCC后端及汇编发布(9)
- GCC后端及汇编发布(10)
- GCC后端及汇编发布(11)
- GCC后端及汇编发布(12)
- GCC后端及汇编发布(13)
- GCC后端及汇编发布(14)
- GCC后端及汇编发布(15)
- GCC后端及汇编发布(16)
- GCC后端及汇编发布(17)
- symbian文件和目录
- 【转】10年软件开发教会我最重要的10件事
- GCC's bacl-end & assemble emission (26)
- 设置java虚拟机内存
- 什么是Unicode编码?
- GCC后端及汇编发布(27)
- 使用UNICODE提高效率
- linux-liveUSB安装
- C/C++连接数据库MySQL(自己写的一个通讯录软件,供大家学习交流)
- JAVAME基础知识 J2ME
- VC下显示位图的几种方法
- VC下显示位图的几种方法
- VC下显示位图的几种方法
- 眼睛泄露你的心灵