Merge remote-tracking branch 'origin/master' into llvm12
This commit is contained in:
@@ -221,7 +221,8 @@ pub const Instruction = union(enum) {
|
||||
offset: u12,
|
||||
opc: u2,
|
||||
op1: u2,
|
||||
fixed: u4 = 0b111_0,
|
||||
v: u1,
|
||||
fixed: u3 = 0b111,
|
||||
size: u2,
|
||||
},
|
||||
LoadStorePairOfRegisters: packed struct {
|
||||
@@ -505,6 +506,7 @@ pub const Instruction = union(enum) {
|
||||
.offset = offset.toU12(),
|
||||
.opc = opc,
|
||||
.op1 = op1,
|
||||
.v = 0,
|
||||
.size = 0b10,
|
||||
},
|
||||
};
|
||||
@@ -517,6 +519,7 @@ pub const Instruction = union(enum) {
|
||||
.offset = offset.toU12(),
|
||||
.opc = opc,
|
||||
.op1 = op1,
|
||||
.v = 0,
|
||||
.size = 0b11,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -222,7 +222,7 @@ pub const LLVMIRModule = struct {
|
||||
|
||||
var error_message: [*:0]const u8 = undefined;
|
||||
var target: *const llvm.Target = undefined;
|
||||
if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message)) {
|
||||
if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message).toBool()) {
|
||||
defer llvm.disposeMessage(error_message);
|
||||
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
@@ -306,7 +306,7 @@ pub const LLVMIRModule = struct {
|
||||
// verifyModule always allocs the error_message even if there is no error
|
||||
defer llvm.disposeMessage(error_message);
|
||||
|
||||
if (self.llvm_module.verify(.ReturnStatus, &error_message)) {
|
||||
if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) {
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
try stderr.print("broken LLVM module found: {s}\nThis is a bug in the Zig compiler.", .{error_message});
|
||||
return error.BrokenLLVMModule;
|
||||
@@ -322,7 +322,7 @@ pub const LLVMIRModule = struct {
|
||||
object_pathZ.ptr,
|
||||
.ObjectFile,
|
||||
&error_message,
|
||||
)) {
|
||||
).toBool()) {
|
||||
defer llvm.disposeMessage(error_message);
|
||||
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
@@ -617,7 +617,7 @@ pub const LLVMIRModule = struct {
|
||||
|
||||
var indices: [2]*const llvm.Value = .{
|
||||
index_type.constNull(),
|
||||
index_type.constInt(1, false),
|
||||
index_type.constInt(1, .False),
|
||||
};
|
||||
|
||||
return self.builder.buildLoad(self.builder.buildInBoundsGEP(operand, &indices, 2, ""), "");
|
||||
@@ -679,7 +679,7 @@ pub const LLVMIRModule = struct {
|
||||
const signed = inst.base.ty.isSignedInt();
|
||||
// TODO: Should we use intcast here or just a simple bitcast?
|
||||
// LLVM does truncation vs bitcast (+signed extension) in the intcast depending on the sizes
|
||||
return self.builder.buildIntCast2(val, try self.getLLVMType(inst.base.ty, inst.base.src), signed, "");
|
||||
return self.builder.buildIntCast2(val, try self.getLLVMType(inst.base.ty, inst.base.src), llvm.Bool.fromBool(signed), "");
|
||||
}
|
||||
|
||||
fn genBitCast(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {
|
||||
@@ -785,7 +785,7 @@ pub const LLVMIRModule = struct {
|
||||
if (bigint.limbs.len != 1) {
|
||||
return self.fail(src, "TODO implement bigger bigint", .{});
|
||||
}
|
||||
const llvm_int = llvm_type.constInt(bigint.limbs[0], false);
|
||||
const llvm_int = llvm_type.constInt(bigint.limbs[0], .False);
|
||||
if (!bigint.positive) {
|
||||
return llvm.constNeg(llvm_int);
|
||||
}
|
||||
@@ -823,7 +823,7 @@ pub const LLVMIRModule = struct {
|
||||
return self.fail(src, "TODO handle other sentinel values", .{});
|
||||
} else false;
|
||||
|
||||
return self.context.constString(payload.data.ptr, @intCast(c_uint, payload.data.len), !zero_sentinel);
|
||||
return self.context.constString(payload.data.ptr, @intCast(c_uint, payload.data.len), llvm.Bool.fromBool(!zero_sentinel));
|
||||
} else {
|
||||
return self.fail(src, "TODO handle more array values", .{});
|
||||
}
|
||||
@@ -839,13 +839,13 @@ pub const LLVMIRModule = struct {
|
||||
llvm_child_type.constNull(),
|
||||
self.context.intType(1).constNull(),
|
||||
};
|
||||
return self.context.constStruct(&optional_values, 2, false);
|
||||
return self.context.constStruct(&optional_values, 2, .False);
|
||||
} else {
|
||||
var optional_values: [2]*const llvm.Value = .{
|
||||
try self.genTypedValue(src, .{ .ty = child_type, .val = tv.val }),
|
||||
self.context.intType(1).constAllOnes(),
|
||||
};
|
||||
return self.context.constStruct(&optional_values, 2, false);
|
||||
return self.context.constStruct(&optional_values, 2, .False);
|
||||
}
|
||||
} else {
|
||||
return self.fail(src, "TODO implement const of optional pointer", .{});
|
||||
@@ -885,7 +885,7 @@ pub const LLVMIRModule = struct {
|
||||
try self.getLLVMType(child_type, src),
|
||||
self.context.intType(1),
|
||||
};
|
||||
return self.context.structType(&optional_types, 2, false);
|
||||
return self.context.structType(&optional_types, 2, .False);
|
||||
} else {
|
||||
return self.fail(src, "TODO implement optional pointers as actual pointers", .{});
|
||||
}
|
||||
@@ -937,7 +937,7 @@ pub const LLVMIRModule = struct {
|
||||
try self.getLLVMType(return_type, src),
|
||||
if (fn_param_len == 0) null else llvm_param.ptr,
|
||||
@intCast(c_uint, fn_param_len),
|
||||
false,
|
||||
.False,
|
||||
);
|
||||
const llvm_fn = self.llvm_module.addFunction(func.name, fn_type);
|
||||
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
//! We do this instead of @cImport because the self-hosted compiler is easier
|
||||
//! to bootstrap if it does not depend on translate-c.
|
||||
|
||||
const LLVMBool = bool;
|
||||
/// Do not compare directly to .True, use toBool() instead.
|
||||
pub const Bool = enum(c_int) {
|
||||
False,
|
||||
True,
|
||||
_,
|
||||
|
||||
pub fn fromBool(b: bool) Bool {
|
||||
return @intToEnum(Bool, @boolToInt(b));
|
||||
}
|
||||
|
||||
pub fn toBool(b: Bool) bool {
|
||||
return b != .False;
|
||||
}
|
||||
};
|
||||
pub const AttributeIndex = c_uint;
|
||||
|
||||
/// Make sure to use the *InContext functions instead of the global ones.
|
||||
@@ -22,13 +35,13 @@ pub const Context = opaque {
|
||||
extern fn LLVMVoidTypeInContext(C: *const Context) *const Type;
|
||||
|
||||
pub const structType = LLVMStructTypeInContext;
|
||||
extern fn LLVMStructTypeInContext(C: *const Context, ElementTypes: [*]*const Type, ElementCount: c_uint, Packed: LLVMBool) *const Type;
|
||||
extern fn LLVMStructTypeInContext(C: *const Context, ElementTypes: [*]*const Type, ElementCount: c_uint, Packed: Bool) *const Type;
|
||||
|
||||
pub const constString = LLVMConstStringInContext;
|
||||
extern fn LLVMConstStringInContext(C: *const Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: LLVMBool) *const Value;
|
||||
extern fn LLVMConstStringInContext(C: *const Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) *const Value;
|
||||
|
||||
pub const constStruct = LLVMConstStructInContext;
|
||||
extern fn LLVMConstStructInContext(C: *const Context, ConstantVals: [*]*const Value, Count: c_uint, Packed: LLVMBool) *const Value;
|
||||
extern fn LLVMConstStructInContext(C: *const Context, ConstantVals: [*]*const Value, Count: c_uint, Packed: Bool) *const Value;
|
||||
|
||||
pub const createBasicBlock = LLVMCreateBasicBlockInContext;
|
||||
extern fn LLVMCreateBasicBlockInContext(C: *const Context, Name: [*:0]const u8) *const BasicBlock;
|
||||
@@ -59,7 +72,7 @@ pub const Value = opaque {
|
||||
|
||||
pub const Type = opaque {
|
||||
pub const functionType = LLVMFunctionType;
|
||||
extern fn LLVMFunctionType(ReturnType: *const Type, ParamTypes: ?[*]*const Type, ParamCount: c_uint, IsVarArg: LLVMBool) *const Type;
|
||||
extern fn LLVMFunctionType(ReturnType: *const Type, ParamTypes: ?[*]*const Type, ParamCount: c_uint, IsVarArg: Bool) *const Type;
|
||||
|
||||
pub const constNull = LLVMConstNull;
|
||||
extern fn LLVMConstNull(Ty: *const Type) *const Value;
|
||||
@@ -68,7 +81,7 @@ pub const Type = opaque {
|
||||
extern fn LLVMConstAllOnes(Ty: *const Type) *const Value;
|
||||
|
||||
pub const constInt = LLVMConstInt;
|
||||
extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: LLVMBool) *const Value;
|
||||
extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: Bool) *const Value;
|
||||
|
||||
pub const constArray = LLVMConstArray;
|
||||
extern fn LLVMConstArray(ElementTy: *const Type, ConstantVals: ?[*]*const Value, Length: c_uint) *const Value;
|
||||
@@ -91,7 +104,7 @@ pub const Module = opaque {
|
||||
extern fn LLVMDisposeModule(*const Module) void;
|
||||
|
||||
pub const verify = LLVMVerifyModule;
|
||||
extern fn LLVMVerifyModule(*const Module, Action: VerifierFailureAction, OutMessage: *[*:0]const u8) LLVMBool;
|
||||
extern fn LLVMVerifyModule(*const Module, Action: VerifierFailureAction, OutMessage: *[*:0]const u8) Bool;
|
||||
|
||||
pub const addFunction = LLVMAddFunction;
|
||||
extern fn LLVMAddFunction(*const Module, Name: [*:0]const u8, FunctionTy: *const Type) *const Value;
|
||||
@@ -191,7 +204,7 @@ pub const Builder = opaque {
|
||||
extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||
|
||||
pub const buildIntCast2 = LLVMBuildIntCast2;
|
||||
extern fn LLVMBuildIntCast2(*const Builder, Val: *const Value, DestTy: *const Type, IsSigned: LLVMBool, Name: [*:0]const u8) *const Value;
|
||||
extern fn LLVMBuildIntCast2(*const Builder, Val: *const Value, DestTy: *const Type, IsSigned: Bool, Name: [*:0]const u8) *const Value;
|
||||
|
||||
pub const buildBitCast = LLVMBuildBitCast;
|
||||
extern fn LLVMBuildBitCast(*const Builder, Val: *const Value, DestTy: *const Type, Name: [*:0]const u8) *const Value;
|
||||
@@ -258,7 +271,7 @@ pub const TargetMachine = opaque {
|
||||
Filename: [*:0]const u8,
|
||||
codegen: CodeGenFileType,
|
||||
ErrorMessage: *[*:0]const u8,
|
||||
) LLVMBool;
|
||||
) Bool;
|
||||
};
|
||||
|
||||
pub const CodeMode = extern enum {
|
||||
@@ -295,7 +308,7 @@ pub const CodeGenFileType = extern enum {
|
||||
|
||||
pub const Target = opaque {
|
||||
pub const getFromTriple = LLVMGetTargetFromTriple;
|
||||
extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) LLVMBool;
|
||||
extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) Bool;
|
||||
};
|
||||
|
||||
extern fn LLVMInitializeAArch64TargetInfo() void;
|
||||
|
||||
@@ -95,7 +95,7 @@ pub const Context = struct {
|
||||
return switch (ty.tag()) {
|
||||
.f32 => wasm.valtype(.f32),
|
||||
.f64 => wasm.valtype(.f64),
|
||||
.u32, .i32 => wasm.valtype(.i32),
|
||||
.u32, .i32, .bool => wasm.valtype(.i32),
|
||||
.u64, .i64 => wasm.valtype(.i64),
|
||||
else => self.fail(src, "TODO - Wasm genValtype for type '{s}'", .{ty.tag()}),
|
||||
};
|
||||
@@ -208,6 +208,7 @@ pub const Context = struct {
|
||||
.alloc => self.genAlloc(inst.castTag(.alloc).?),
|
||||
.arg => self.genArg(inst.castTag(.arg).?),
|
||||
.block => self.genBlock(inst.castTag(.block).?),
|
||||
.breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),
|
||||
.br => self.genBr(inst.castTag(.br).?),
|
||||
.call => self.genCall(inst.castTag(.call).?),
|
||||
.cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),
|
||||
@@ -221,9 +222,11 @@ pub const Context = struct {
|
||||
.dbg_stmt => WValue.none,
|
||||
.load => self.genLoad(inst.castTag(.load).?),
|
||||
.loop => self.genLoop(inst.castTag(.loop).?),
|
||||
.not => self.genNot(inst.castTag(.not).?),
|
||||
.ret => self.genRet(inst.castTag(.ret).?),
|
||||
.retvoid => WValue.none,
|
||||
.store => self.genStore(inst.castTag(.store).?),
|
||||
.unreach => self.genUnreachable(inst.castTag(.unreach).?),
|
||||
else => self.fail(inst.src, "TODO: Implement wasm inst: {s}", .{inst.tag}),
|
||||
};
|
||||
}
|
||||
@@ -329,7 +332,7 @@ pub const Context = struct {
|
||||
try writer.writeByte(wasm.opcode(.i32_const));
|
||||
try leb.writeILEB128(writer, inst.val.toUnsignedInt());
|
||||
},
|
||||
.i32 => {
|
||||
.i32, .bool => {
|
||||
try writer.writeByte(wasm.opcode(.i32_const));
|
||||
try leb.writeILEB128(writer, inst.val.toSignedInt());
|
||||
},
|
||||
@@ -414,7 +417,14 @@ pub const Context = struct {
|
||||
|
||||
// insert blocks at the position of `offset` so
|
||||
// the condition can jump to it
|
||||
const offset = condition.code_offset;
|
||||
const offset = switch (condition) {
|
||||
.code_offset => |offset| offset,
|
||||
else => blk: {
|
||||
const offset = self.code.items.len;
|
||||
try self.emitWValue(condition);
|
||||
break :blk offset;
|
||||
},
|
||||
};
|
||||
const block_ty = try self.genBlockType(condbr.base.src, condbr.base.ty);
|
||||
try self.startBlock(.block, block_ty, offset);
|
||||
|
||||
@@ -523,4 +533,32 @@ pub const Context = struct {
|
||||
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genNot(self: *Context, not: *Inst.UnOp) InnerError!WValue {
|
||||
const offset = self.code.items.len;
|
||||
|
||||
const operand = self.resolveInst(not.operand);
|
||||
try self.emitWValue(operand);
|
||||
|
||||
// wasm does not have booleans nor the `not` instruction, therefore compare with 0
|
||||
// to create the same logic
|
||||
const writer = self.code.writer();
|
||||
try writer.writeByte(wasm.opcode(.i32_const));
|
||||
try leb.writeILEB128(writer, @as(i32, 0));
|
||||
|
||||
try writer.writeByte(wasm.opcode(.i32_eq));
|
||||
|
||||
return WValue{ .code_offset = offset };
|
||||
}
|
||||
|
||||
fn genBreakpoint(self: *Context, breakpoint: *Inst.NoOp) InnerError!WValue {
|
||||
// unsupported by wasm itself. Can be implemented once we support DWARF
|
||||
// for wasm
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genUnreachable(self: *Context, unreach: *Inst.NoOp) InnerError!WValue {
|
||||
try self.code.append(wasm.opcode(.@"unreachable"));
|
||||
return .none;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user