From: David Schleef Date: Wed, 18 Mar 2009 01:47:06 +0000 (-0700) Subject: Add neon target X-Git-Tag: orc-0.4.5~22^2~157 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=307661838a1b2dd9af7c9d092d3397cfe60da189;p=platform%2Fupstream%2Forc.git Add neon target --- diff --git a/orc/Makefile.am b/orc/Makefile.am index c90e83b..6e85300 100644 --- a/orc/Makefile.am +++ b/orc/Makefile.am @@ -26,6 +26,8 @@ liborc_@ORC_MAJORMINOR@_la_SOURCES = \ orcrules-mmx.c \ orcrules-sse.c \ orcrules-arm.c \ + orcprogram-neon.c \ + orcrules-neon.c \ orcdebug.c \ orccpu.c \ orcutils.c \ diff --git a/orc/orc.c b/orc/orc.c index e55515a..c930a03 100644 --- a/orc/orc.c +++ b/orc/orc.c @@ -23,6 +23,7 @@ orc_init (void) orc_mmx_init(); orc_sse_init(); orc_powerpc_init(); + orc_neon_init(); orc_arm_init(); } diff --git a/orc/orcprogram-neon.c b/orc/orcprogram-neon.c new file mode 100644 index 0000000..9e4c6e8 --- /dev/null +++ b/orc/orcprogram-neon.c @@ -0,0 +1,358 @@ + +#include "config.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#define SIZE 65536 + +int neon_exec_ptr = ARM_V1; + +void neon_emit_loop (OrcCompiler *compiler); + +void orc_compiler_neon_register_rules (OrcTarget *target); + +void orc_compiler_neon_init (OrcCompiler *compiler); +void orc_compiler_neon_assemble (OrcCompiler *compiler); + +void orc_compiler_rewrite_vars (OrcCompiler *compiler); +void orc_compiler_dump (OrcCompiler *compiler); + +void neon_loadw (OrcCompiler *compiler, int dest, int src1, int offset); +void neon_storew (OrcCompiler *compiler, int dest, int offset, int src1); + +void +neon_emit_prologue (OrcCompiler *compiler) +{ + unsigned int regs = 0; + int i; + + orc_compiler_append_code(compiler,".global %s\n", compiler->program->name); + orc_compiler_append_code(compiler,"%s:\n", compiler->program->name); + + for(i=0;i<16;i++){ + if (compiler->used_regs[ORC_GP_REG_BASE + i] && + compiler->save_regs[ORC_GP_REG_BASE + i]) { + regs |= (1<used_regs[ORC_GP_REG_BASE + i] && + compiler->save_regs[ORC_GP_REG_BASE + i]) { + regs |= (1<valid_regs[i] = 1; + } + for(i=ORC_VEC_REG_BASE+3;ivalid_regs[i] = 1; + } + compiler->valid_regs[ARM_V1] = 0; + //compiler->valid_regs[ARM_SB] = 0; + compiler->valid_regs[ARM_IP] = 0; + compiler->valid_regs[ARM_SP] = 0; + compiler->valid_regs[ARM_LR] = 0; + compiler->valid_regs[ARM_PC] = 0; + for(i=4;i<11;i++) { + compiler->save_regs[ORC_GP_REG_BASE+i] = 1; + } + + for(i=0;ialloc_regs[i] = 0; + compiler->used_regs[i] = 0; + } + + compiler->loop_shift = 0; +} + +void +neon_load_constants (OrcCompiler *compiler) +{ + int i; + for(i=0;in_vars;i++){ + switch (compiler->vars[i].vartype) { + case ORC_VAR_TYPE_CONST: + //arm_emit_loadiw (compiler, compiler->vars[i].alloc, + // (int)compiler->vars[i].value); + break; + case ORC_VAR_TYPE_PARAM: + //arm_emit_loadw (compiler, compiler->vars[i].alloc, + // (int)ORC_STRUCT_OFFSET(OrcExecutor, params[i]), neon_exec_ptr); + break; + case ORC_VAR_TYPE_SRC: + case ORC_VAR_TYPE_DEST: + arm_emit_load_reg (compiler, + compiler->vars[i].ptr_register, + neon_exec_ptr, ORC_STRUCT_OFFSET(OrcExecutor, arrays[i])); + break; + default: + break; + } + } +} + +void +neon_emit_load_src (OrcCompiler *compiler, OrcVariable *var) +{ + int ptr_reg; + if (var->ptr_register == 0) { + int i; + i = var - compiler->vars; + //arm_emit_mov_memoffset_reg (compiler, arm_ptr_size, + // (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[i]), + // neon_exec_ptr, X86_ECX); + ptr_reg = ARM_PC; + } else { + ptr_reg = var->ptr_register; + } + switch (var->size << compiler->loop_shift) { + //case 1: + //arm_emit_mov_memoffset_reg (compiler, 1, 0, ptr_reg, X86_ECX); + //arm_emit_mov_reg_arm (compiler, X86_ECX, var->alloc); + break; + case 2: + neon_loadw (compiler, var->alloc, ptr_reg, 0); + //arm_emit_mov_memoffset_reg (compiler, 2, 0, ptr_reg, X86_ECX); + //arm_emit_mov_reg_arm (compiler, X86_ECX, var->alloc); + break; + //case 4: + //arm_emit_mov_memoffset_arm (compiler, 4, 0, ptr_reg, var->alloc); + break; + //case 8: + //arm_emit_mov_memoffset_arm (compiler, 8, 0, ptr_reg, var->alloc); + break; + //case 16: + //arm_emit_mov_memoffset_arm (compiler, 16, 0, ptr_reg, var->alloc); + break; + default: + ORC_PROGRAM_ERROR(compiler, "bad size %d\n", var->size << compiler->loop_shift); + } +} + +void +neon_emit_store_dest (OrcCompiler *compiler, OrcVariable *var) +{ + int ptr_reg; + if (var->ptr_register == 0) { + //arm_emit_mov_memoffset_reg (compiler, arm_ptr_size, + // var->ptr_offset, neon_exec_ptr, X86_ECX); + ptr_reg = ARM_PC; + } else { + ptr_reg = var->ptr_register; + } + switch (var->size << compiler->loop_shift) { + case 1: + //arm_emit_mov_arm_reg (compiler, var->alloc, X86_ECX); + //arm_emit_mov_reg_memoffset (compiler, 1, X86_ECX, 0, ptr_reg); + break; + case 2: + neon_storew (compiler, ptr_reg, 0, var->alloc); + //arm_emit_mov_arm_reg (compiler, var->alloc, X86_ECX); + //arm_emit_mov_reg_memoffset (compiler, 2, X86_ECX, 0, ptr_reg); + break; + case 4: + //arm_emit_mov_arm_memoffset (compiler, 4, var->alloc, 0, ptr_reg, + // var->is_aligned, var->is_uncached); + break; + case 8: + //arm_emit_mov_arm_memoffset (compiler, 8, var->alloc, 0, ptr_reg, + // var->is_aligned, var->is_uncached); + break; + case 16: + //arm_emit_mov_arm_memoffset (compiler, 16, var->alloc, 0, ptr_reg, + // var->is_aligned, var->is_uncached); + break; + default: + ORC_PROGRAM_ERROR(compiler, "bad size %d\n", var->size << compiler->loop_shift); + } +} + +void +orc_compiler_neon_assemble (OrcCompiler *compiler) +{ + int dest_var = orc_compiler_get_dest (compiler); + + compiler->vars[dest_var].is_aligned = FALSE; + + neon_emit_prologue (compiler); + + arm_emit_load_reg (compiler, ARM_IP, neon_exec_ptr, + (int)ORC_STRUCT_OFFSET(OrcExecutor,n)); + neon_load_constants (compiler); + + arm_emit_label (compiler, 1); + + arm_emit_cmp_imm (compiler, ARM_IP, 0); + arm_emit_branch (compiler, ARM_COND_EQ, 3); + + arm_emit_label (compiler, 2); + neon_emit_loop (compiler); + arm_emit_sub_imm (compiler, ARM_IP, ARM_IP, 1); + arm_emit_cmp_imm (compiler, ARM_IP, 0); + arm_emit_branch (compiler, ARM_COND_NE, 2); + arm_emit_label (compiler, 3); + + neon_emit_epilogue (compiler); + + arm_do_fixups (compiler); +} + +void +neon_emit_loop (OrcCompiler *compiler) +{ + int j; + int k; + OrcInstruction *insn; + OrcStaticOpcode *opcode; + OrcRule *rule; + + for(j=0;jn_insns;j++){ + insn = compiler->insns + j; + opcode = insn->opcode; + + orc_compiler_append_code(compiler,"# %d: %s", j, insn->opcode->name); + + /* set up args */ +#if 0 + for(k=0;kn_src + opcode->n_dest;k++){ + args[k] = compiler->vars + insn->args[k]; + orc_compiler_append_code(compiler," %d", args[k]->alloc); + if (args[k]->is_chained) { + orc_compiler_append_code(compiler," (chained)"); + } + } +#endif + orc_compiler_append_code(compiler,"\n"); + + for(k=0;ksrc_size[k] == 0) continue; + + switch (compiler->vars[insn->src_args[k]].vartype) { + case ORC_VAR_TYPE_SRC: + neon_emit_load_src (compiler, &compiler->vars[insn->src_args[k]]); + break; + case ORC_VAR_TYPE_CONST: + break; + case ORC_VAR_TYPE_PARAM: + break; + case ORC_VAR_TYPE_TEMP: + break; + default: + break; + } + } + + rule = insn->rule; + if (rule && rule->emit) { + if (compiler->vars[insn->dest_args[0]].alloc != + compiler->vars[insn->src_args[0]].alloc) { + arm_emit_mov (compiler, compiler->vars[insn->src_args[0]].alloc, + compiler->vars[insn->dest_args[0]].alloc); + } + rule->emit (compiler, rule->emit_user, insn); + } else { + orc_compiler_append_code(compiler,"No rule for: %s\n", opcode->name); + } + + for(k=0;kdest_size[k] == 0) continue; + + switch (compiler->vars[insn->dest_args[k]].vartype) { + case ORC_VAR_TYPE_DEST: + neon_emit_store_dest (compiler, &compiler->vars[insn->dest_args[k]]); + break; + case ORC_VAR_TYPE_TEMP: + break; + default: + break; + } + } + } + + for(k=0;kn_vars;k++){ + if (compiler->vars[k].vartype == ORC_VAR_TYPE_SRC || + compiler->vars[k].vartype == ORC_VAR_TYPE_DEST) { + if (compiler->vars[k].ptr_register) { + //arm_emit_add_imm_reg (compiler, arm_ptr_size, + // compiler->vars[k].size << compiler->loop_shift, + // compiler->vars[k].ptr_register); + } else { + //arm_emit_add_imm_memoffset (compiler, arm_ptr_size, + // compiler->vars[k].size << compiler->loop_shift, + // (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[k]), + // neon_exec_ptr); + } + } + } +} + diff --git a/orc/orcprogram.h b/orc/orcprogram.h index 7bc33a9..86b4084 100644 --- a/orc/orcprogram.h +++ b/orc/orcprogram.h @@ -382,6 +382,7 @@ void orc_sse_init (void); void orc_arm_init (void); void orc_powerpc_init (void); void orc_c_init (void); +void orc_neon_init (void); OrcCompileResult orc_program_compile (OrcProgram *p); OrcCompileResult orc_program_compile_for_target (OrcProgram *p, OrcTarget *target); diff --git a/orc/orcrules-neon.c b/orc/orcrules-neon.c new file mode 100644 index 0000000..cb316e5 --- /dev/null +++ b/orc/orcrules-neon.c @@ -0,0 +1,266 @@ + +#include "config.h" + +#include +#include +#include + +#include +#include + +#include +#include + + +const char *neon_reg_name (int reg) +{ + static const char *vec_regs[] = { + "d0", "d1", "d2", "d3", + "d4", "d5", "d6", "d7", + "d8", "d9", "d10", "d11", + "d12", "d13", "d14", "d15" }; + + if (reg < ORC_VEC_REG_BASE || reg >= ORC_VEC_REG_BASE+16) { + return "ERROR"; + } + + return vec_regs[reg&0xf]; +} + +void +neon_loadw (OrcCompiler *compiler, int dest, int src1, int offset) +{ + uint32_t code; + + code = 0xed900b00; + code |= (src1&0xf) << 16; + code |= (dest&0xf) << 12; + code |= (offset&0xf0) << 4; + code |= offset&0x0f; + + ORC_ASM_CODE(compiler," vldr.64 %s, [%s, #%d]\n", + neon_reg_name (dest), + arm_reg_name (src1), offset); + arm_emit (compiler, code); +} + +void +neon_storew (OrcCompiler *compiler, int dest, int offset, int src1) +{ + uint32_t code; + + code = 0xed800b00; + code |= (dest&0xf) << 16; + code |= (src1&0xf) << 12; + code |= (offset&0xf0) << 4; + code |= offset&0x0f; + + ORC_ASM_CODE(compiler," vstr.64 %s, [%s, #%d]\n", + neon_reg_name (src1), + arm_reg_name (dest), offset); + arm_emit (compiler, code); +} + +#define UNARY(opcode,insn_name,code) \ +static void \ +neon_rule_ ## opcode (OrcCompiler *p, void *user, OrcInstruction *insn) \ +{ \ + uint32_t x = code; \ + ORC_ASM_CODE(p," " insn_name " %s, %s\n", \ + neon_reg_name (p->vars[insn->dest_args[0]].alloc), \ + neon_reg_name (p->vars[insn->src_args[0]].alloc)); \ + x |= (p->vars[insn->dest_args[0]].alloc&0xf)<<12; \ + x |= (p->vars[insn->src_args[0]].alloc&0xf)<<0; \ + arm_emit (p, x); \ +} + +#define BINARY(opcode,insn_name,code) \ +static void \ +neon_rule_ ## opcode (OrcCompiler *p, void *user, OrcInstruction *insn) \ +{ \ + uint32_t x = code; \ + ORC_ASM_CODE(p," " insn_name " %s, %s, %s\n", \ + neon_reg_name (p->vars[insn->dest_args[0]].alloc), \ + neon_reg_name (p->vars[insn->src_args[0]].alloc), \ + neon_reg_name (p->vars[insn->src_args[1]].alloc)); \ + x |= (p->vars[insn->dest_args[0]].alloc&0xf)<<16; \ + x |= (p->vars[insn->src_args[0]].alloc&0xf)<<12; \ + x |= (p->vars[insn->src_args[1]].alloc&0xf)<<0; \ + arm_emit (p, x); \ +} + +#define MOVE(opcode,insn_name,code) \ +static void \ +neon_rule_ ## opcode (OrcCompiler *p, void *user, OrcInstruction *insn) \ +{ \ + uint32_t x = code; \ + ORC_ASM_CODE(p," " insn_name " %s, %s\n", \ + neon_reg_name (p->vars[insn->dest_args[0]].alloc), \ + neon_reg_name (p->vars[insn->src_args[0]].alloc)); \ + x |= (p->vars[insn->dest_args[0]].alloc&0xf)<<16; \ + x |= (p->vars[insn->src_args[0]].alloc&0xf)<<12; \ + x |= (p->vars[insn->src_args[0]].alloc&0xf)<<0; \ + arm_emit (p, x); \ +} + +#define SHIFT(opcode,insn_name,code) \ +static void \ +neon_rule_ ## opcode (OrcCompiler *p, void *user, OrcInstruction *insn) \ +{ \ + uint32_t x = code; \ + ORC_ASM_CODE(p," " insn_name " %s, %s, #2\n", \ + neon_reg_name (p->vars[insn->dest_args[0]].alloc), \ + neon_reg_name (p->vars[insn->src_args[0]].alloc)); \ + x |= (p->vars[insn->dest_args[0]].alloc&0xf)<<12; \ + x |= (p->vars[insn->src_args[0]].alloc&0xf)<<0; \ + arm_emit (p, x); \ +} + + + +UNARY(absb,"vabs.s8",0xf3b10300) +BINARY(addb,"vadd.i8",0xf2000800) +BINARY(addssb,"vqadd.s8",0xf2000010) +BINARY(addusb,"vqadd.u8",0xf3000010) +BINARY(andb,"vand",0xf2000110) +BINARY(cmpeqb,"vceq.i8",0xf3000810) +BINARY(cmpgtsb,"vcgt.s8",0xf2000300) +MOVE(copyb,"vmov",0xf2200110) +BINARY(maxsb,"vmax.s8",0xf2000600) +BINARY(maxub,"vmax.u8",0xf3000600) +BINARY(minsb,"vmin.s8",0xf2000610) +BINARY(minub,"vmin.u8",0xf3000610) +BINARY(mullb,"vmul.i8",0xf2000910) +BINARY(orb,"vorn",0xf2300110) +SHIFT(shlb,"vshl.i8",0xf2890510) +SHIFT(shrsb,"vshr.s8",0xf28f0010) +SHIFT(shrub,"vshr.u8",0xf38f0010) +BINARY(subb,"vsub.i8",0xf3000800) +BINARY(subssb,"vqsub.s8",0xf2000210) +BINARY(subusb,"vqsub.u8",0xf3000210) +BINARY(xorb,"veor",0xf3000110) + +UNARY(absw,"vabs.s16",0xf3b50300) +BINARY(addw,"vadd.i16",0xf2100800) +BINARY(addssw,"vqadd.s16",0xf2100010) +BINARY(addusw,"vqadd.u16",0xf3100010) +BINARY(andw,"vand",0xf2000110) +BINARY(cmpeqw,"vceq.i16",0xf3100810) +BINARY(cmpgtsw,"vcgt.s16",0xf2100300) +MOVE(copyw,"vmov",0xf2200110) +BINARY(maxsw,"vmax.s16",0xf2100600) +BINARY(maxuw,"vmax.u16",0xf3100600) +BINARY(minsw,"vmin.s16",0xf2100610) +BINARY(minuw,"vmin.u16",0xf3100610) +BINARY(mullw,"vmul.i16",0xf2100910) +BINARY(orw,"vorn",0xf2300110) +SHIFT(shlw,"vshl.i16",0xf2910510) +SHIFT(shrsw,"vshr.s16",0xf29f0010) +SHIFT(shruw,"vshr.u16",0xf39f0010) +BINARY(subw,"vsub.i16",0xf3100800) +BINARY(subssw,"vqsub.s16",0xf2100210) +BINARY(subusw,"vqsub.u16",0xf3100210) +BINARY(xorw,"veor",0xf3000110) + +UNARY(absl,"vabs.s32",0xf3b90300) +BINARY(addl,"vadd.i32",0xf2200800) +BINARY(addssl,"vqadd.s32",0xf2200010) +BINARY(addusl,"vqadd.u32",0xf3200010) +BINARY(andl,"vand",0xf2000110) +BINARY(cmpeql,"vceq.i32",0xf3200810) +BINARY(cmpgtsl,"vcgt.s32",0xf2200300) +MOVE(copyl,"vmov",0xf2200110) +BINARY(maxsl,"vmax.s32",0xf2200600) +BINARY(maxul,"vmax.u32",0xf3200600) +BINARY(minsl,"vmin.s32",0xf2200610) +BINARY(minul,"vmin.u32",0xf3200610) +BINARY(mulll,"vmul.i32",0xf2200910) +BINARY(orl,"vorn",0xf2300110) +SHIFT(shll,"vshl.i32",0xf2a10510) +SHIFT(shrsl,"vshr.s32",0xf2bf0010) +SHIFT(shrul,"vshr.u32",0xf3bf0010) +BINARY(subl,"vsub.i32",0xf3200800) +BINARY(subssl,"vqsub.s32",0xf2200210) +BINARY(subusl,"vqsub.u32",0xf3200210) +BINARY(xorl,"veor",0xf3000110) + + + +void +orc_compiler_neon_register_rules (OrcTarget *target) +{ + OrcRuleSet *rule_set; + + rule_set = orc_rule_set_new (orc_opcode_set_get("sys"), target); + +#define REG(x) \ + orc_rule_register (rule_set, #x , neon_rule_ ## x, NULL) + + REG(absb); + REG(addb); + REG(addssb); + REG(addusb); + REG(andb); + REG(cmpeqb); + REG(cmpgtsb); + REG(copyb); + REG(maxsb); + REG(maxub); + REG(minsb); + REG(minub); + REG(mullb); + REG(orb); + REG(shlb); + REG(shrsb); + REG(shrub); + REG(subb); + REG(subssb); + REG(subusb); + REG(xorb); + + REG(absw); + REG(addw); + REG(addssw); + REG(addusw); + REG(andw); + REG(cmpeqw); + REG(cmpgtsw); + REG(copyw); + REG(maxsw); + REG(maxuw); + REG(minsw); + REG(minuw); + REG(mullw); + REG(orw); + REG(shlw); + REG(shrsw); + REG(shruw); + REG(subw); + REG(subssw); + REG(subusw); + REG(xorw); + + REG(absl); + REG(addl); + REG(addssl); + REG(addusl); + REG(andl); + REG(cmpeql); + REG(cmpgtsl); + REG(copyl); + REG(maxsl); + REG(maxul); + REG(minsl); + REG(minul); + REG(mulll); + REG(orl); + REG(shll); + REG(shrsl); + REG(shrul); + REG(subl); + REG(subssl); + REG(subusl); + REG(xorl); + +} + diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index ee30e71..4a65851 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -18,6 +18,9 @@ orcbin_PROGRAMS = $(TESTS) CLEANFILES = temp-orc-test-* +TESTS += test6 +noinst_PROGRAMS += test6 + AM_CFLAGS = $(ORC_CFLAGS) LIBS = $(ORC_LIBS) $(top_builddir)/orc-test/liborc-test-0.3.la diff --git a/testsuite/test6.c b/testsuite/test6.c new file mode 100644 index 0000000..c143bbc --- /dev/null +++ b/testsuite/test6.c @@ -0,0 +1,115 @@ + +#include "config.h" + +#include +#include + +#include + +#define PREFIX "/opt/arm-2008q3/bin/arm-none-linux-gnueabi-" + +int error = FALSE; + +void test_opcode (const char *name); + +int +main (int argc, char *argv[]) +{ + int i; + OrcOpcodeSet *opcode_set; + + orc_init(); + + opcode_set = orc_opcode_set_get ("sys"); + + for(i=0;in_opcodes;i++){ + printf("/* %s %d,%d,%d %p */\n", + opcode_set->opcodes[i].name, + opcode_set->opcodes[i].dest_size[0], + opcode_set->opcodes[i].src_size[0], + opcode_set->opcodes[i].src_size[1], + opcode_set->opcodes[i].emulate); + test_opcode (opcode_set->opcodes[i].name); + } + + if (error) return 1; + return 0; +} + +void +test_opcode (const char *name) +{ + OrcProgram *p; + char s[40]; + char cmd[200]; + int ret; + FILE *file; + + p = orc_program_new_dss (2,2,2); + + sprintf(s, "test_%s", name); + orc_program_set_name (p, s); + orc_program_add_constant (p, 2, 1, "c1"); + + orc_program_append_str (p, name, "d1", "s1", "c1"); + + ret = orc_program_compile_for_target (p, orc_target_get_by_name("neon")); + if (!ret) { + error = TRUE; + goto out; + } + + fflush (stdout); + + file = fopen ("tmp-test6.s", "w"); + fprintf(file, "%s", orc_program_get_asm_code (p)); + fclose (file); + + file = fopen ("dump", "w"); + ret = fwrite(p->code, p->code_size, 1, file); + fclose (file); + + ret = system (PREFIX "gcc -mcpu=cortex-a8 -mfpu=neon -Wall -c tmp-test6.s"); + if (ret != 0) { + printf("gcc failed\n"); + error = TRUE; + goto out; + } + + ret = system (PREFIX "objdump -dr tmp-test6.o >tmp-test6.dis"); + if (ret != 0) { + printf("objdump failed\n"); + error = TRUE; + goto out; + } + + sprintf (cmd, PREFIX "objcopy -I binary -O elf32-littlearm -B arm " + "--rename-section .data=.text " + "--redefine-sym _binary_dump_start=%s " + "dump tmp-test6.o", s); + ret = system (cmd); + if (ret != 0) { + printf("objcopy failed\n"); + error = TRUE; + goto out; + } + + ret = system (PREFIX "objdump -Dr tmp-test6.o >tmp-test6-dump.dis"); + if (ret != 0) { + printf("objdump failed\n"); + error = TRUE; + goto out; + } + + ret = system ("diff -u tmp-test6.dis tmp-test6-dump.dis"); + if (ret != 0) { + printf("diff failed\n"); + error = TRUE; + goto out; + } + +out: + orc_program_free (p); +} + +