aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2016-12-13 04:30:41 -0500
committerAndrew Kelley <superjoe30@gmail.com>2016-12-13 04:30:41 -0500
commit3f3630d7e349361116416dce36d2f69d7c3e318c (patch)
tree836ce54c606706f23a0a7524a3628b6e464c051c /src/codegen.cpp
parent8bb5f54b292efacc03ff8d7cc6f59ae36c24305d (diff)
downloadzig-3f3630d7e349361116416dce36d2f69d7c3e318c.tar.gz
zig-3f3630d7e349361116416dce36d2f69d7c3e318c.zip
IR: implement the rest of the builtin functions
* returnAddress * frameAddress * addWithOverflow * subWithOverflow * mulWithOverflow * shlWithOverflow * alignOf
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp85
1 files changed, 85 insertions, 0 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index f89fb84f69..78a07ed3d1 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -2058,6 +2058,80 @@ static LLVMValueRef ir_render_breakpoint(CodeGen *g, IrExecutable *executable, I
return nullptr;
}
+static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executable,
+ IrInstructionReturnAddress *instruction)
+{
+ LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
+ return LLVMBuildCall(g->builder, g->return_address_fn_val, &zero, 1, "");
+}
+
+static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable,
+ IrInstructionFrameAddress *instruction)
+{
+ LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
+ return LLVMBuildCall(g->builder, g->frame_address_fn_val, &zero, 1, "");
+}
+
+static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {
+ TypeTableEntry *int_type = get_underlying_type(instruction->result_ptr_type);
+ assert(int_type->id == TypeTableEntryIdInt);
+
+ LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
+ LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);
+ LLVMValueRef ptr_result = ir_llvm_value(g, instruction->result_ptr);
+
+ LLVMValueRef result = LLVMBuildShl(g->builder, op1, op2, "");
+ LLVMValueRef orig_val;
+ if (int_type->data.integral.is_signed) {
+ orig_val = LLVMBuildAShr(g->builder, result, op2, "");
+ } else {
+ orig_val = LLVMBuildLShr(g->builder, result, op2, "");
+ }
+ LLVMValueRef overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, op1, orig_val, "");
+
+ LLVMBuildStore(g->builder, result, ptr_result);
+
+ return overflow_bit;
+}
+
+static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable, IrInstructionOverflowOp *instruction) {
+ AddSubMul add_sub_mul;
+ switch (instruction->op) {
+ case IrOverflowOpAdd:
+ add_sub_mul = AddSubMulAdd;
+ break;
+ case IrOverflowOpSub:
+ add_sub_mul = AddSubMulAdd;
+ break;
+ case IrOverflowOpMul:
+ add_sub_mul = AddSubMulAdd;
+ break;
+ case IrOverflowOpShl:
+ return render_shl_with_overflow(g, instruction);
+ }
+
+ TypeTableEntry *int_type = get_underlying_type(instruction->result_ptr_type);
+ assert(int_type->id == TypeTableEntryIdInt);
+
+ LLVMValueRef fn_val = get_int_overflow_fn(g, int_type, add_sub_mul);
+
+ LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
+ LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);
+ LLVMValueRef ptr_result = ir_llvm_value(g, instruction->result_ptr);
+
+ LLVMValueRef params[] = {
+ op1,
+ op2,
+ };
+
+ LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
+ LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
+ LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
+ LLVMBuildStore(g->builder, result, ptr_result);
+
+ return overflow_bit;
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -2100,6 +2174,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdEmbedFile:
case IrInstructionIdIntType:
case IrInstructionIdMemberCount:
+ case IrInstructionIdAlignOf:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -2169,6 +2244,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_slice(g, executable, (IrInstructionSlice *)instruction);
case IrInstructionIdBreakpoint:
return ir_render_breakpoint(g, executable, (IrInstructionBreakpoint *)instruction);
+ case IrInstructionIdReturnAddress:
+ return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);
+ case IrInstructionIdFrameAddress:
+ return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);
+ case IrInstructionIdOverflowOp:
+ return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
case IrInstructionIdSwitchVar:
case IrInstructionIdContainerInitList:
case IrInstructionIdStructInit:
@@ -3300,6 +3381,8 @@ static void define_builtin_fns(CodeGen *g) {
&g->builtin_types.entry_i32->type_ref, 1, false);
builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type);
assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
+
+ g->return_address_fn_val = builtin_fn->fn_val;
}
{
BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdFrameAddress,
@@ -3310,6 +3393,8 @@ static void define_builtin_fns(CodeGen *g) {
&g->builtin_types.entry_i32->type_ref, 1, false);
builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.frameaddress", fn_type);
assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
+
+ g->frame_address_fn_val = builtin_fn->fn_val;
}
{
BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);